浏览代码

basically playing

Laserlicht 2 年之前
父节点
当前提交
8de4b88a1b
共有 5 个文件被更改,包括 134 次插入63 次删除
  1. 2 0
      client/CMT.cpp
  2. 1 2
      client/CMusicHandler.cpp
  3. 1 1
      client/CMusicHandler.h
  4. 126 54
      client/CVideoHandler.cpp
  5. 4 6
      client/CVideoHandler.h

+ 2 - 0
client/CMT.cpp

@@ -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))

+ 1 - 2
client/CMusicHandler.cpp

@@ -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_LoadWAV_RW(ops, 1);	// will free ops
+		Mix_Chunk *chunk = Mix_QuickLoad_RAW(data.first.get(), (int)data.second);
 
 
 		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))});

+ 1 - 1
client/CMusicHandler.h

@@ -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);
 
 

+ 126 - 54
client/CVideoHandler.cpp

@@ -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)
 {
 {
+	std::pair<std::unique_ptr<ui8 []>, si64> dat(std::make_pair(std::make_unique<ui8[]>(0), 0));
+
+	VideoPath fnameAudio;
+
+	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;
 	AVPacket packet;
-	std::pair<std::unique_ptr<ui8 []>, si64> data;
 
 
-	std::vector<double> samples;
-	while (av_read_frame(format, &packet) >= 0)
+	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.

+ 4 - 6
client/CVideoHandler.h

@@ -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