mirror of
https://github.com/vcmi/vcmi.git
synced 2025-11-27 22:49:25 +02:00
basically playing
This commit is contained in:
@@ -423,6 +423,8 @@ int main(int argc, char * argv[])
|
|||||||
//plays intro, ends when intro is over or button has been pressed (handles events)
|
//plays intro, ends when intro is over or button has been pressed (handles events)
|
||||||
void playIntro()
|
void playIntro()
|
||||||
{
|
{
|
||||||
|
auto audioData = CCS->videoh->getAudio(VideoPath::builtin("3DOLOGO.SMK"));
|
||||||
|
CCS->soundh->playSound(audioData);
|
||||||
if(CCS->videoh->openAndPlayVideo(VideoPath::builtin("3DOLOGO.SMK"), 0, 1, true, true))
|
if(CCS->videoh->openAndPlayVideo(VideoPath::builtin("3DOLOGO.SMK"), 0, 1, true, true))
|
||||||
{
|
{
|
||||||
if (CCS->videoh->openAndPlayVideo(VideoPath::builtin("NWCLOGO.SMK"), 0, 1, true, true))
|
if (CCS->videoh->openAndPlayVideo(VideoPath::builtin("NWCLOGO.SMK"), 0, 1, true, true))
|
||||||
|
|||||||
@@ -151,8 +151,7 @@ Mix_Chunk *CSoundHandler::GetSoundChunk(std::pair<std::unique_ptr<ui8 []>, si64>
|
|||||||
if (cache && soundChunksRaw.find(startBytes) != soundChunksRaw.end())
|
if (cache && soundChunksRaw.find(startBytes) != soundChunksRaw.end())
|
||||||
return soundChunksRaw[startBytes].first;
|
return soundChunksRaw[startBytes].first;
|
||||||
|
|
||||||
SDL_RWops *ops = SDL_RWFromMem(data.first.get(), (int)data.second);
|
Mix_Chunk *chunk = Mix_QuickLoad_RAW(data.first.get(), (int)data.second);
|
||||||
Mix_Chunk *chunk = Mix_LoadWAV_RW(ops, 1); // will free ops
|
|
||||||
|
|
||||||
if (cache)
|
if (cache)
|
||||||
soundChunksRaw.insert({startBytes, std::make_pair (chunk, std::move (data.first))});
|
soundChunksRaw.insert({startBytes, std::make_pair (chunk, std::move (data.first))});
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ public:
|
|||||||
// Sounds
|
// Sounds
|
||||||
int playSound(soundBase::soundID soundID, int repeats=0);
|
int playSound(soundBase::soundID soundID, int repeats=0);
|
||||||
int playSound(const AudioPath & sound, int repeats=0, bool cache=false);
|
int playSound(const AudioPath & sound, int repeats=0, bool cache=false);
|
||||||
int playSound(std::pair<std::unique_ptr<ui8 []>, si64> & data, int repeats, bool cache=false);
|
int playSound(std::pair<std::unique_ptr<ui8 []>, si64> & data, int repeats=0, bool cache=false);
|
||||||
int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec);
|
int playSoundFromSet(std::vector<soundBase::soundID> &sound_vec);
|
||||||
void stopSound(int handler);
|
void stopSound(int handler);
|
||||||
|
|
||||||
|
|||||||
@@ -55,6 +55,24 @@ static si64 lodSeek(void * opaque, si64 pos, int whence)
|
|||||||
return video->data->seek(pos);
|
return video->data->seek(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Define a set of functions to read data
|
||||||
|
static int lodReadAudio(void* opaque, uint8_t* buf, int size)
|
||||||
|
{
|
||||||
|
auto video = reinterpret_cast<CVideoPlayer *>(opaque);
|
||||||
|
|
||||||
|
return static_cast<int>(video->dataAudio->read(buf, size));
|
||||||
|
}
|
||||||
|
|
||||||
|
static si64 lodSeekAudio(void * opaque, si64 pos, int whence)
|
||||||
|
{
|
||||||
|
auto video = reinterpret_cast<CVideoPlayer *>(opaque);
|
||||||
|
|
||||||
|
if (whence & AVSEEK_SIZE)
|
||||||
|
return video->dataAudio->getSize();
|
||||||
|
|
||||||
|
return video->dataAudio->seek(pos);
|
||||||
|
}
|
||||||
|
|
||||||
CVideoPlayer::CVideoPlayer()
|
CVideoPlayer::CVideoPlayer()
|
||||||
: stream(-1)
|
: stream(-1)
|
||||||
, format (nullptr)
|
, format (nullptr)
|
||||||
@@ -127,17 +145,6 @@ bool CVideoPlayer::open(const VideoPath & videoToOpen, bool loop, bool useOverla
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the first audio stream
|
|
||||||
streamAudio = -1;
|
|
||||||
for(ui32 i=0; i<format->nb_streams; i++)
|
|
||||||
{
|
|
||||||
if (format->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
|
||||||
{
|
|
||||||
streamAudio = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream < 0)
|
if (stream < 0)
|
||||||
// No video stream in that file
|
// No video stream in that file
|
||||||
return false;
|
return false;
|
||||||
@@ -145,12 +152,6 @@ bool CVideoPlayer::open(const VideoPath & videoToOpen, bool loop, bool useOverla
|
|||||||
// Find the decoder for the video stream
|
// Find the decoder for the video stream
|
||||||
codec = avcodec_find_decoder(format->streams[stream]->codecpar->codec_id);
|
codec = avcodec_find_decoder(format->streams[stream]->codecpar->codec_id);
|
||||||
|
|
||||||
if(streamAudio > -1)
|
|
||||||
{
|
|
||||||
// Find the decoder for the audio stream
|
|
||||||
codecAudio = avcodec_find_decoder(format->streams[streamAudio]->codecpar->codec_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (codec == nullptr)
|
if (codec == nullptr)
|
||||||
{
|
{
|
||||||
// Unsupported codec
|
// Unsupported codec
|
||||||
@@ -160,10 +161,6 @@ bool CVideoPlayer::open(const VideoPath & videoToOpen, bool loop, bool useOverla
|
|||||||
codecContext = avcodec_alloc_context3(codec);
|
codecContext = avcodec_alloc_context3(codec);
|
||||||
if(!codecContext)
|
if(!codecContext)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (codecAudio != nullptr)
|
|
||||||
codecContextAudio = avcodec_alloc_context3(codecAudio);
|
|
||||||
|
|
||||||
// Get a pointer to the codec context for the video stream
|
// Get a pointer to the codec context for the video stream
|
||||||
int ret = avcodec_parameters_to_context(codecContext, format->streams[stream]->codecpar);
|
int ret = avcodec_parameters_to_context(codecContext, format->streams[stream]->codecpar);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
@@ -173,17 +170,6 @@ bool CVideoPlayer::open(const VideoPath & videoToOpen, bool loop, bool useOverla
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get a pointer to the codec context for the audio stream
|
|
||||||
if (streamAudio > -1)
|
|
||||||
{
|
|
||||||
ret = avcodec_parameters_to_context(codecContextAudio, format->streams[streamAudio]->codecpar);
|
|
||||||
if (ret < 0)
|
|
||||||
{
|
|
||||||
//We cannot get codec from parameters
|
|
||||||
avcodec_free_context(&codecContextAudio);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open codec
|
// Open codec
|
||||||
if ( avcodec_open2(codecContext, codec, nullptr) < 0 )
|
if ( avcodec_open2(codecContext, codec, nullptr) < 0 )
|
||||||
{
|
{
|
||||||
@@ -194,18 +180,6 @@ bool CVideoPlayer::open(const VideoPath & videoToOpen, bool loop, bool useOverla
|
|||||||
// Allocate video frame
|
// Allocate video frame
|
||||||
frame = av_frame_alloc();
|
frame = av_frame_alloc();
|
||||||
|
|
||||||
// Open codec
|
|
||||||
if (codecAudio != nullptr)
|
|
||||||
{
|
|
||||||
if ( avcodec_open2(codecContextAudio, codecAudio, nullptr) < 0 )
|
|
||||||
{
|
|
||||||
// Could not open codec
|
|
||||||
codecAudio = nullptr;
|
|
||||||
}
|
|
||||||
// Allocate audio frame
|
|
||||||
frameAudio = av_frame_alloc();
|
|
||||||
}
|
|
||||||
|
|
||||||
//setup scaling
|
//setup scaling
|
||||||
if(scale)
|
if(scale)
|
||||||
{
|
{
|
||||||
@@ -275,8 +249,6 @@ bool CVideoPlayer::open(const VideoPath & videoToOpen, bool loop, bool useOverla
|
|||||||
if (sws == nullptr)
|
if (sws == nullptr)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
playVideoAudio();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,28 +453,128 @@ void CVideoPlayer::close()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CVideoPlayer::playVideoAudio()
|
std::pair<std::unique_ptr<ui8 []>, si64> CVideoPlayer::getAudio(const VideoPath & videoToOpen)
|
||||||
{
|
{
|
||||||
AVPacket packet;
|
std::pair<std::unique_ptr<ui8 []>, si64> dat(std::make_pair(std::make_unique<ui8[]>(0), 0));
|
||||||
std::pair<std::unique_ptr<ui8 []>, si64> data;
|
|
||||||
|
|
||||||
std::vector<double> samples;
|
VideoPath fnameAudio;
|
||||||
while (av_read_frame(format, &packet) >= 0)
|
|
||||||
|
if (CResourceHandler::get()->existsResource(videoToOpen))
|
||||||
|
fnameAudio = videoToOpen;
|
||||||
|
else
|
||||||
|
fnameAudio = videoToOpen.addPrefix("VIDEO/");
|
||||||
|
|
||||||
|
if (!CResourceHandler::get()->existsResource(fnameAudio))
|
||||||
|
{
|
||||||
|
logGlobal->error("Error: video %s was not found", fnameAudio.getName());
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataAudio = CResourceHandler::get()->load(fnameAudio);
|
||||||
|
|
||||||
|
static const int BUFFER_SIZE = 4096;
|
||||||
|
|
||||||
|
unsigned char * bufferAudio = (unsigned char *)av_malloc(BUFFER_SIZE);// will be freed by ffmpeg
|
||||||
|
AVIOContext * contextAudio = avio_alloc_context( bufferAudio, BUFFER_SIZE, 0, (void *)this, lodReadAudio, nullptr, lodSeekAudio);
|
||||||
|
|
||||||
|
AVFormatContext * formatAudio = avformat_alloc_context();
|
||||||
|
formatAudio->pb = contextAudio;
|
||||||
|
// filename is not needed - file was already open and stored in this->data;
|
||||||
|
int avfopen = avformat_open_input(&formatAudio, "dummyFilename", nullptr, nullptr);
|
||||||
|
|
||||||
|
if (avfopen != 0)
|
||||||
|
{
|
||||||
|
return dat;
|
||||||
|
}
|
||||||
|
// Retrieve stream information
|
||||||
|
if (avformat_find_stream_info(formatAudio, nullptr) < 0)
|
||||||
|
return dat;
|
||||||
|
|
||||||
|
// Find the first audio stream
|
||||||
|
int streamAudio = -1;
|
||||||
|
for(ui32 i=0; i<formatAudio->nb_streams; i++)
|
||||||
|
{
|
||||||
|
if (formatAudio->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
|
||||||
|
{
|
||||||
|
streamAudio = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(streamAudio < 0)
|
||||||
|
return dat;
|
||||||
|
|
||||||
|
const AVCodec *codecAudio = avcodec_find_decoder(formatAudio->streams[streamAudio]->codecpar->codec_id);
|
||||||
|
|
||||||
|
AVCodecContext *codecContextAudio;
|
||||||
|
if (codecAudio != nullptr)
|
||||||
|
codecContextAudio = avcodec_alloc_context3(codecAudio);
|
||||||
|
|
||||||
|
// Get a pointer to the codec context for the audio stream
|
||||||
|
if (streamAudio > -1)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
ret = avcodec_parameters_to_context(codecContextAudio, formatAudio->streams[streamAudio]->codecpar);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
//We cannot get codec from parameters
|
||||||
|
avcodec_free_context(&codecContextAudio);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open codec
|
||||||
|
AVFrame *frameAudio;
|
||||||
|
if (codecAudio != nullptr)
|
||||||
|
{
|
||||||
|
if ( avcodec_open2(codecContextAudio, codecAudio, nullptr) < 0 )
|
||||||
|
{
|
||||||
|
// Could not open codec
|
||||||
|
codecAudio = nullptr;
|
||||||
|
}
|
||||||
|
// Allocate audio frame
|
||||||
|
frameAudio = av_frame_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
|
AVPacket packet;
|
||||||
|
|
||||||
|
std::vector<ui8> samples;
|
||||||
|
while (av_read_frame(formatAudio, &packet) >= 0)
|
||||||
{
|
{
|
||||||
avcodec_send_packet(codecContextAudio, &packet);
|
avcodec_send_packet(codecContextAudio, &packet);
|
||||||
avcodec_receive_frame(codecContextAudio, frameAudio);
|
avcodec_receive_frame(codecContextAudio, frameAudio);
|
||||||
|
|
||||||
data.second = frameAudio->linesize[0];
|
|
||||||
data.first = (new ui8[data.second]);
|
|
||||||
|
|
||||||
for (int s = 0; s < frameAudio->linesize[0]; s+=sizeof(ui8))
|
for (int s = 0; s < frameAudio->linesize[0]; s+=sizeof(ui8))
|
||||||
{
|
{
|
||||||
ui8 value;
|
ui8 value;
|
||||||
memcpy(&value, &frameAudio->data[0][s], sizeof(ui8));
|
memcpy(&value, &frameAudio->data[0][s], sizeof(ui8));
|
||||||
samples.push_back(value);
|
samples.push_back(value);
|
||||||
data.first.
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dat = std::pair<std::unique_ptr<ui8 []>, si64>(std::make_pair(std::make_unique<ui8[]>(samples.size()), samples.size()));
|
||||||
|
std::copy(samples.begin(), samples.end(), dat.first.get());
|
||||||
|
|
||||||
|
if (frameAudio)
|
||||||
|
av_frame_free(&frameAudio);
|
||||||
|
|
||||||
|
if (codecAudio)
|
||||||
|
{
|
||||||
|
avcodec_close(codecContextAudio);
|
||||||
|
codecAudio = nullptr;
|
||||||
|
}
|
||||||
|
if (codecContextAudio)
|
||||||
|
avcodec_free_context(&codecContextAudio);
|
||||||
|
|
||||||
|
if (formatAudio)
|
||||||
|
avformat_close_input(&formatAudio);
|
||||||
|
|
||||||
|
if (contextAudio)
|
||||||
|
{
|
||||||
|
av_free(contextAudio);
|
||||||
|
contextAudio = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dat;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Plays a video. Only works for overlays.
|
// Plays a video. Only works for overlays.
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ public:
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
virtual std::pair<std::unique_ptr<ui8 []>, si64> getAudio(const VideoPath & videoToOpen) { return std::pair<std::unique_ptr<ui8 []>, si64>(std::make_pair(std::make_unique<ui8[]>(0), 0)); };
|
||||||
};
|
};
|
||||||
|
|
||||||
class CEmptyVideoPlayer : public IMainVideoPlayer
|
class CEmptyVideoPlayer : public IMainVideoPlayer
|
||||||
@@ -68,14 +69,10 @@ VCMI_LIB_NAMESPACE_END
|
|||||||
class CVideoPlayer : public IMainVideoPlayer
|
class CVideoPlayer : public IMainVideoPlayer
|
||||||
{
|
{
|
||||||
int stream; // stream index in video
|
int stream; // stream index in video
|
||||||
int streamAudio; // stream index in audio
|
|
||||||
AVFormatContext *format;
|
AVFormatContext *format;
|
||||||
AVCodecContext *codecContext; // codec context for stream
|
AVCodecContext *codecContext; // codec context for stream
|
||||||
AVCodecContext *codecContextAudio; // codec context for stream
|
|
||||||
const AVCodec *codec;
|
const AVCodec *codec;
|
||||||
const AVCodec *codecAudio;
|
|
||||||
AVFrame *frame;
|
AVFrame *frame;
|
||||||
AVFrame *frameAudio;
|
|
||||||
struct SwsContext *sws;
|
struct SwsContext *sws;
|
||||||
|
|
||||||
AVIOContext * context;
|
AVIOContext * context;
|
||||||
@@ -95,8 +92,6 @@ class CVideoPlayer : public IMainVideoPlayer
|
|||||||
|
|
||||||
bool playVideo(int x, int y, bool stopOnKey);
|
bool playVideo(int x, int y, bool stopOnKey);
|
||||||
bool open(const VideoPath & fname, bool loop, bool useOverlay = false, bool scale = false);
|
bool open(const VideoPath & fname, bool loop, bool useOverlay = false, bool scale = false);
|
||||||
|
|
||||||
void playVideoAudio();
|
|
||||||
public:
|
public:
|
||||||
CVideoPlayer();
|
CVideoPlayer();
|
||||||
~CVideoPlayer();
|
~CVideoPlayer();
|
||||||
@@ -113,6 +108,8 @@ public:
|
|||||||
// Opens video, calls playVideo, closes video; returns playVideo result (if whole video has been played)
|
// Opens video, calls playVideo, closes video; returns playVideo result (if whole video has been played)
|
||||||
bool openAndPlayVideo(const VideoPath & name, int x, int y, bool stopOnKey = false, bool scale = false) override;
|
bool openAndPlayVideo(const VideoPath & name, int x, int y, bool stopOnKey = false, bool scale = false) override;
|
||||||
|
|
||||||
|
std::pair<std::unique_ptr<ui8 []>, si64> getAudio(const VideoPath & videoToOpen) override;
|
||||||
|
|
||||||
VideoPath videoName() override {return fname;};
|
VideoPath videoName() override {return fname;};
|
||||||
|
|
||||||
//TODO:
|
//TODO:
|
||||||
@@ -122,6 +119,7 @@ public:
|
|||||||
|
|
||||||
// public to allow access from ffmpeg IO functions
|
// public to allow access from ffmpeg IO functions
|
||||||
std::unique_ptr<CInputStream> data;
|
std::unique_ptr<CInputStream> data;
|
||||||
|
std::unique_ptr<CInputStream> dataAudio;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user