播放视频时同时播放音频
This commit is contained in:
		@@ -99,16 +99,19 @@ struct VideoParam
 | 
				
			|||||||
	int width;
 | 
						int width;
 | 
				
			||||||
	int height;
 | 
						int height;
 | 
				
			||||||
	int videoStreamIndex;
 | 
						int videoStreamIndex;
 | 
				
			||||||
 | 
						AVStream* stream;
 | 
				
			||||||
	bool eof = false;
 | 
						bool eof = false;
 | 
				
			||||||
	bool pause = false;
 | 
						bool pause = false;
 | 
				
			||||||
	bool quit = false;
 | 
						bool quit = false;
 | 
				
			||||||
 | 
						double totalTime = 0;
 | 
				
			||||||
 | 
						double currentTime = 0;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct AudioParam
 | 
					struct AudioParam
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	MediaQueue<AVPacket> packetQueue;
 | 
						MediaQueue<AVPacket> packetQueue;
 | 
				
			||||||
	AVCodecContext* codecCtx;
 | 
						AVCodecContext* codecCtx;
 | 
				
			||||||
 | 
						AVStream* stream;
 | 
				
			||||||
	int audioStreamIndex;
 | 
						int audioStreamIndex;
 | 
				
			||||||
	static constexpr int MAX_BUFFER_SIZE = 192000;
 | 
						static constexpr int MAX_BUFFER_SIZE = 192000;
 | 
				
			||||||
	uint8_t* buffer = new uint8_t[MAX_BUFFER_SIZE];
 | 
						uint8_t* buffer = new uint8_t[MAX_BUFFER_SIZE];
 | 
				
			||||||
@@ -118,6 +121,16 @@ struct AudioParam
 | 
				
			|||||||
	bool pause = false;
 | 
						bool pause = false;
 | 
				
			||||||
	bool isVideo = false;
 | 
						bool isVideo = false;
 | 
				
			||||||
	bool quit = false;
 | 
						bool quit = false;
 | 
				
			||||||
 | 
						double currentTime = 0;
 | 
				
			||||||
 | 
						double totalTime = 0;
 | 
				
			||||||
 | 
						double lastPts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						double getCurrentTime() const
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							const int diff = bufferSize - bufferIndex;
 | 
				
			||||||
 | 
							const int bytePreSec = codecCtx->sample_rate * codecCtx->ch_layout.nb_channels * 2;
 | 
				
			||||||
 | 
							return currentTime - static_cast<double>(diff) / bytePreSec;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct MediaParam
 | 
					struct MediaParam
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -4,6 +4,6 @@
 | 
				
			|||||||
#include "decodeParam.h"
 | 
					#include "decodeParam.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void InitDecoder(const char* filepath, MediaParam& param);
 | 
					void InitDecoder(const char* filepath, MediaParam& param);
 | 
				
			||||||
void RequestVideoPacket(MediaParam& param);
 | 
					void RequestMediaPacket(MediaParam& param);
 | 
				
			||||||
void RequestVideoFrame(MediaParam& param);
 | 
					void RequestVideoFrame(MediaParam& param);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										8
									
								
								main.cc
									
									
									
									
									
								
							
							
						
						
									
										8
									
								
								main.cc
									
									
									
									
									
								
							@@ -29,8 +29,8 @@ int InitAudio(SDL_Window* window, SDL_Renderer* renderer, const char* targetFile
 | 
				
			|||||||
		InitDecoder(targetFilePath, param);
 | 
							InitDecoder(targetFilePath, param);
 | 
				
			||||||
		window = SDL_CreateWindow("mp", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
 | 
							window = SDL_CreateWindow("mp", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN);
 | 
				
			||||||
		renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
 | 
							renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
		std::jthread(RequestAudioPacket, std::ref(param)).detach();
 | 
							std::jthread(RequestAudioPacket, std::ref(param)).detach();
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	SDL_AudioSpec des;
 | 
						SDL_AudioSpec des;
 | 
				
			||||||
	des.freq = param.audioParam.codecCtx->sample_rate;
 | 
						des.freq = param.audioParam.codecCtx->sample_rate;
 | 
				
			||||||
	des.channels = param.audioParam.codecCtx->ch_layout.nb_channels;
 | 
						des.channels = param.audioParam.codecCtx->ch_layout.nb_channels;
 | 
				
			||||||
@@ -55,7 +55,7 @@ int InitVideo(SDL_Window*& window, const char* targetFilepath, MediaParam& param
 | 
				
			|||||||
	param.audioParam.isVideo = true;
 | 
						param.audioParam.isVideo = true;
 | 
				
			||||||
	InitAudio(nullptr, nullptr, nullptr, param);
 | 
						InitAudio(nullptr, nullptr, nullptr, param);
 | 
				
			||||||
	//FIX: when app exited, the fmtCtx was freed, so need notify decode thread to stop decode and exit.
 | 
						//FIX: when app exited, the fmtCtx was freed, so need notify decode thread to stop decode and exit.
 | 
				
			||||||
	std::jthread(RequestVideoPacket, std::ref(param)).detach();
 | 
						std::jthread(RequestMediaPacket, std::ref(param)).detach();
 | 
				
			||||||
	std::jthread(RequestVideoFrame, std::ref(param)).detach();
 | 
						std::jthread(RequestVideoFrame, std::ref(param)).detach();
 | 
				
			||||||
	const int client_width = param.videoParam.width / 2;
 | 
						const int client_width = param.videoParam.width / 2;
 | 
				
			||||||
	const int client_height = param.videoParam.height / 2;
 | 
						const int client_height = param.videoParam.height / 2;
 | 
				
			||||||
@@ -221,7 +221,7 @@ int main(int argc, char** argv)
 | 
				
			|||||||
	case FileType::VIDEO:
 | 
						case FileType::VIDEO:
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		InitVideo(window, targetFilepath, mediaParam, openglVideoParam, shaderService);
 | 
							InitVideo(window, targetFilepath, mediaParam, openglVideoParam, shaderService);
 | 
				
			||||||
		const auto stream_frame_rate = mediaParam.fmtCtx->streams[mediaParam.videoParam.videoStreamIndex]->avg_frame_rate;
 | 
							const auto stream_frame_rate = mediaParam.videoParam.stream->avg_frame_rate;
 | 
				
			||||||
		framerate = static_cast<double>(stream_frame_rate.den) / stream_frame_rate.num;
 | 
							framerate = static_cast<double>(stream_frame_rate.den) / stream_frame_rate.num;
 | 
				
			||||||
		break;
 | 
							break;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@@ -272,7 +272,7 @@ int main(int argc, char** argv)
 | 
				
			|||||||
		case FileType::VIDEO:
 | 
							case FileType::VIDEO:
 | 
				
			||||||
			OpenglRenderVideo(mediaParam, openglVideoParam, shaderService);
 | 
								OpenglRenderVideo(mediaParam, openglVideoParam, shaderService);
 | 
				
			||||||
			SDL_GL_SwapWindow(window);
 | 
								SDL_GL_SwapWindow(window);
 | 
				
			||||||
			std::this_thread::sleep_until(current_time + std::chrono::milliseconds(30));
 | 
								std::this_thread::sleep_until(current_time + std::chrono::milliseconds(static_cast<int>(framerate * 1000)));
 | 
				
			||||||
			current_time = std::chrono::system_clock::now();
 | 
								current_time = std::chrono::system_clock::now();
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		case FileType::IMG:
 | 
							case FileType::IMG:
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,10 @@ int RequestAudioFrame(AudioParam& param, uint8_t* audioBuffer, int bufSize, SDL_
 | 
				
			|||||||
	if (!param.packetQueue.pop(&packet, true)) {
 | 
						if (!param.packetQueue.pop(&packet, true)) {
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if (packet.pts != AV_NOPTS_VALUE)
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							param.currentTime = av_q2d(param.stream->time_base) * packet.pts;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
	int ret = avcodec_send_packet(param.codecCtx, &packet);
 | 
						int ret = avcodec_send_packet(param.codecCtx, &packet);
 | 
				
			||||||
	if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
 | 
						if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
 | 
				
			||||||
		return -1;
 | 
							return -1;
 | 
				
			||||||
@@ -55,9 +59,9 @@ int RequestAudioFrame(AudioParam& param, uint8_t* audioBuffer, int bufSize, SDL_
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	for (int i = 0; i < nbSamples; i++)
 | 
						for (int i = 0; i < nbSamples; i++)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		double magnitude = sqrt(fftwOutput[i][0] * fftwOutput[i][0] + fftwOutput[i][1] * fftwOutput[i][1]);
 | 
							//double magnitude = sqrt(fftwOutput[i][0] * fftwOutput[i][0] + fftwOutput[i][1] * fftwOutput[i][1]);
 | 
				
			||||||
		double phase = atan2(fftwOutput[i][1], fftwOutput[i][0]);
 | 
							//double phase = atan2(fftwOutput[i][1], fftwOutput[i][0]);
 | 
				
			||||||
		std::cout << "mag: " << magnitude << "\n phase: " << phase << "\n";
 | 
							//std::cout << "mag: " << magnitude << "\n phase: " << phase << "\n";
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	constexpr AVSampleFormat dstFormat = AV_SAMPLE_FMT_S16;
 | 
						constexpr AVSampleFormat dstFormat = AV_SAMPLE_FMT_S16;
 | 
				
			||||||
@@ -79,6 +83,7 @@ int RequestAudioFrame(AudioParam& param, uint8_t* audioBuffer, int bufSize, SDL_
 | 
				
			|||||||
		SDL_RenderDrawLine(renderer, 0, 0, 300, 300);
 | 
							SDL_RenderDrawLine(renderer, 0, 0, 300, 300);
 | 
				
			||||||
		SDL_RenderPresent(renderer);
 | 
							SDL_RenderPresent(renderer);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						param.currentTime += static_cast<double>(dataSize) / (2 * (param.codecCtx->ch_layout.nb_channels) / param.codecCtx->sample_rate);
 | 
				
			||||||
	av_frame_free(&frame);
 | 
						av_frame_free(&frame);
 | 
				
			||||||
	swr_free(&swrCtx);
 | 
						swr_free(&swrCtx);
 | 
				
			||||||
	return dataSize;
 | 
						return dataSize;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,8 +18,10 @@ void InitDecoder(const char* filepath, MediaParam& param) {
 | 
				
			|||||||
			avcodec_parameters_to_context(codecFmt, stream->codecpar);
 | 
								avcodec_parameters_to_context(codecFmt, stream->codecpar);
 | 
				
			||||||
			avcodec_open2(codecFmt, codec, nullptr);
 | 
								avcodec_open2(codecFmt, codec, nullptr);
 | 
				
			||||||
			param.videoParam.codecCtx = codecFmt;
 | 
								param.videoParam.codecCtx = codecFmt;
 | 
				
			||||||
 | 
								param.videoParam.stream = stream;
 | 
				
			||||||
			param.videoParam.width = codecFmt->width;
 | 
								param.videoParam.width = codecFmt->width;
 | 
				
			||||||
			param.videoParam.height = codecFmt->height;
 | 
								param.videoParam.height = codecFmt->height;
 | 
				
			||||||
 | 
								param.videoParam.totalTime = av_q2d(stream->avg_frame_rate) * stream->duration;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		else if (codec->type == AVMEDIA_TYPE_AUDIO)
 | 
							else if (codec->type == AVMEDIA_TYPE_AUDIO)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
@@ -28,15 +30,16 @@ void InitDecoder(const char* filepath, MediaParam& param) {
 | 
				
			|||||||
			avcodec_parameters_to_context(codecFmt, stream->codecpar);
 | 
								avcodec_parameters_to_context(codecFmt, stream->codecpar);
 | 
				
			||||||
			avcodec_open2(codecFmt, codec, nullptr);
 | 
								avcodec_open2(codecFmt, codec, nullptr);
 | 
				
			||||||
			param.audioParam.codecCtx = codecFmt;
 | 
								param.audioParam.codecCtx = codecFmt;
 | 
				
			||||||
 | 
								param.audioParam.stream = stream;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	param.fmtCtx = fmtCtx;
 | 
						param.fmtCtx = fmtCtx;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void RequestVideoPacket(MediaParam& param) {
 | 
					void RequestMediaPacket(MediaParam& param) {
 | 
				
			||||||
	const auto& fmtCtx = param.fmtCtx;
 | 
						const auto& fmtCtx = param.fmtCtx;
 | 
				
			||||||
	const auto& videoStreamIndex = param.videoParam.videoStreamIndex;
 | 
						const auto& videoStreamIndex = param.videoParam.videoStreamIndex;
 | 
				
			||||||
 | 
						const auto& audioStreamIndex = param.audioParam.audioStreamIndex;
 | 
				
			||||||
	AVPacket* packet = av_packet_alloc();
 | 
						AVPacket* packet = av_packet_alloc();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	while (true) {
 | 
						while (true) {
 | 
				
			||||||
@@ -56,6 +59,11 @@ void RequestVideoPacket(MediaParam& param) {
 | 
				
			|||||||
				param.videoParam.packetQueue.push(packet);
 | 
									param.videoParam.packetQueue.push(packet);
 | 
				
			||||||
				av_packet_unref(packet);
 | 
									av_packet_unref(packet);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
 | 
								else if (packet->stream_index == audioStreamIndex)
 | 
				
			||||||
 | 
								{
 | 
				
			||||||
 | 
									param.audioParam.packetQueue.push(packet);
 | 
				
			||||||
 | 
									av_packet_unref(packet);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
			else if (ret == AVERROR_EOF)
 | 
								else if (ret == AVERROR_EOF)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				param.videoParam.eof = true;
 | 
									param.videoParam.eof = true;
 | 
				
			||||||
@@ -102,6 +110,8 @@ void RequestVideoFrame(MediaParam& param) {
 | 
				
			|||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		param.videoParam.frameQueue.push(frame);
 | 
							param.videoParam.frameQueue.push(frame);
 | 
				
			||||||
 | 
							auto time_duration = av_q2d(param.videoParam.stream->time_base);
 | 
				
			||||||
 | 
							auto pts = frame->best_effort_timestamp;
 | 
				
			||||||
		av_frame_unref(frame);
 | 
							av_frame_unref(frame);
 | 
				
			||||||
		av_packet_unref(packet);
 | 
							av_packet_unref(packet);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user