/** * Ò¶º£»Ô * QQȺ121376426 * http://blog.yundiantech.com/ */ #include "VideoPlayer.h" #include "Audio/PcmVolumeControl.h" #include #include bool VideoPlayer::initPlayer() { mConditon_Video = new Cond; mConditon_Audio = new Cond; mPlayerState = VideoPlayer_Stop; mVideoPlayerCallBack = nullptr; mAudioID = 0; mIsMute = false; mVolume = 1; seek_req = 0; seek_pos = 0; seek_flag_audio = 0; seek_flag_video = 0; seek_time = 0; mIsNeedPause = false; mIsPause = false; mIsQuit = false; mIsReadFinished = false; mIsReadThreadFinished = false; mIsVideoThreadFinished = false; mIsAudioThreadFinished = false; mVideoStartTime = 0; mPauseStartTime = 0; audio_clock = 0; video_clock = 0; mVideoStream = nullptr; mAudioStream = nullptr; pFormatCtx = nullptr; pCodecCtx = nullptr; pCodec = nullptr; aCodecCtx = nullptr; aCodec = nullptr; aFrame = nullptr; aFrame_ReSample = nullptr; swrCtx = nullptr; av_register_all(); //³õʼ»¯FFMPEG µ÷ÓÃÁËÕâ¸ö²ÅÄÜÕý³£Ê¹ÓñàÂëÆ÷ºÍ½âÂëÆ÷ avformat_network_init(); //Ö§³Ö´ò¿ªÍøÂçÎļþ return true; } bool VideoPlayer::startPlay(const std::string &filePath, int videoType) { videoType = videoType; if (mPlayerState != VideoPlayer_Stop) { return false; } mIsQuit = false; mIsPause = false; if (!filePath.empty()) mFilePath = filePath; //Æô¶¯ÐµÄÏß³ÌʵÏÖ¶ÁÈ¡ÊÓÆµÎļþ std::thread([&](VideoPlayer *pointer) { pointer->readVideoFile(); }, this).detach(); return true; } bool VideoPlayer::replay() { stop(); startPlay(mFilePath); return true; } bool VideoPlayer::play() { mIsNeedPause = false; mIsPause = false; if (mPlayerState != VideoPlayer_Pause) { return false; } uint64_t pauseTime = av_gettime() - mVideoStartTime; //ÔÝÍ£Á˶೤ʱ¼ä mVideoStartTime += pauseTime; //½«ÔÝÍ£µÄʱ¼ä¼Óµ½¿ªÊ¼²¥·ÅµÄʱ¼äÉÏ£¬±£Ö¤Í¬²½²»ÊÜÔÝÍ£µÄÓ°Ïì mPlayerState = VideoPlayer_Playing; doPlayerStateChanged(VideoPlayer_Playing, mVideoStream != nullptr, mAudioStream != nullptr); return true; } bool VideoPlayer::pause() { fprintf(stderr, "%s mIsPause=%d \n", __FUNCTION__, mIsPause); mIsPause = true; if (mPlayerState != VideoPlayer_Playing) { return false; } mPauseStartTime = av_gettime(); mPlayerState = VideoPlayer_Pause; emit doPlayerStateChanged(VideoPlayer_Pause, mVideoStream != nullptr, mAudioStream != nullptr); return true; } bool VideoPlayer::stop(bool isWait) { if (mPlayerState == VideoPlayer_Stop) { return false; } mPlayerState = VideoPlayer_Stop; mIsQuit = true; if (isWait) { while(!mIsReadThreadFinished) { mSleep(3); } } return true; } void VideoPlayer::seek(int64_t pos) { if(!seek_req) { seek_pos = pos; seek_req = 1; } } void VideoPlayer::setMute(bool isMute){ mIsMute = isMute; } float VideoPlayer::getVolume() { return mVolume; } void VideoPlayer::setVolume(float value) { mVolume = value; } double VideoPlayer::getCurrentTime() { return audio_clock; } int64_t VideoPlayer::getTotalTime() { return pFormatCtx->duration; } void VideoPlayer::setVideoPlayerCallBack(VideoPlayerCallBack *pointer){ mVideoPlayerCallBack=pointer; } int VideoPlayer::openSDL() { ///´ò¿ªSDL£¬²¢ÉèÖò¥·ÅµÄ¸ñʽΪ:AUDIO_S16LSB Ë«ÉùµÀ£¬44100hz ///ºóÆÚʹÓÃffmpeg½âÂëÍêÒôƵºó£¬ÐèÒªÖØ²ÉÑù³ÉºÍÕâ¸öÒ»ÑùµÄ¸ñʽ£¬·ñÔò²¥·Å»áÓÐÔÓÒô SDL_AudioSpec wanted_spec, spec; int wanted_nb_channels = 2; int samplerate = 44100; wanted_spec.channels = wanted_nb_channels; wanted_spec.freq = samplerate; wanted_spec.format = AUDIO_S16SYS; // ¾ßÌ庬ÒåÇë²é¿´¡°SDLºê¶¨Ò塱²¿·Ö wanted_spec.silence = 0; // 0ָʾ¾²Òô wanted_spec.samples = SDL_AUDIO_BUFFER_SIZE; // ×Ô¶¨ÒåSDL»º³åÇø´óС wanted_spec.callback = sdlAudioCallBackFunc; // »Øµ÷º¯Êý wanted_spec.userdata = this; // ´«¸øÉÏÃæ»Øµ÷º¯ÊýµÄÍâ´øÊý¾Ý int num = SDL_GetNumAudioDevices(0); for (int i=0;i 0) { break; } } /* ¼ì²éʵ¼ÊʹÓõÄÅäÖ㨱£´æÔÚspec,ÓÉSDL_OpenAudio()Ìî³ä£© */ // if (spec.format != AUDIO_S16SYS) if (mAudioID <= 0) { mIsAudioThreadFinished = true; return -1; } fprintf(stderr, "mAudioID=%d\n\n\n\n\n\n", mAudioID); return 0; } void VideoPlayer::closeSDL() { if (mAudioID > 0) { SDL_LockAudioDevice(mAudioID); SDL_PauseAudioDevice(mAudioID, 1); SDL_UnlockAudioDevice(mAudioID); SDL_CloseAudioDevice(mAudioID); } mAudioID = 0; } void VideoPlayer::readVideoFile() { ///SDL³õʼ»¯ÐèÒª·ÅÈë×ÓÏß³ÌÖУ¬·ñÔòÓÐЩµçÄÔ»áÓÐÎÊÌâ¡£ if (SDL_Init(SDL_INIT_AUDIO)) { doOpenSdlFailed(-100); fprintf(stderr, "Could not initialize SDL - %s. \n", SDL_GetError()); return; } mIsReadThreadFinished = false; mIsReadFinished = false; const char * file_path = mFilePath.c_str(); pFormatCtx = nullptr; pCodecCtx = nullptr; pCodec = nullptr; aCodecCtx = nullptr; aCodec = nullptr; aFrame = nullptr; mAudioStream = nullptr; mVideoStream = nullptr; audio_clock = 0; video_clock = 0; int audioStream ,videoStream; //Allocate an AVFormatContext. pFormatCtx = avformat_alloc_context(); AVDictionary* opts = NULL; av_dict_set(&opts, "rtsp_transport", "tcp", 0); //ÉèÖÃtcp or udp£¬Ä¬ÈÏÒ»°ãÓÅÏÈtcpÔÙ³¢ÊÔudp av_dict_set(&opts, "stimeout", "60000000", 0);//ÉèÖó¬Ê±3Ãë if (avformat_open_input(&pFormatCtx, file_path, nullptr, &opts) != 0) { fprintf(stderr, "can't open the file. \n"); doOpenVideoFileFailed(); goto end; } if (avformat_find_stream_info(pFormatCtx, nullptr) < 0) { fprintf(stderr, "Could't find stream infomation.\n"); doOpenVideoFileFailed(); goto end; } videoStream = -1; audioStream = -1; ///Ñ­»·²éÕÒÊÓÆµÖаüº¬µÄÁ÷ÐÅÏ¢£¬ for (int i = 0; i < pFormatCtx->nb_streams; i++) { if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { videoStream = i; } if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audioStream < 0) { audioStream = i; } } doTotalTimeChanged(getTotalTime()); ///´ò¿ªÊÓÆµ½âÂëÆ÷£¬²¢Æô¶¯ÊÓÆµÏß³Ì if (videoStream >= 0) { ///²éÕÒÊÓÆµ½âÂëÆ÷ pCodecCtx = pFormatCtx->streams[videoStream]->codec; pCodec = avcodec_find_decoder(pCodecCtx->codec_id); if (pCodec == nullptr) { fprintf(stderr, "PCodec not found.\n"); doOpenVideoFileFailed(); goto end; } ///´ò¿ªÊÓÆµ½âÂëÆ÷ if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) { fprintf(stderr, "Could not open video codec.\n"); doOpenVideoFileFailed(); goto end; } mVideoStream = pFormatCtx->streams[videoStream]; ///´´½¨Ò»¸öÏß³ÌרÃÅÓÃÀ´½âÂëÊÓÆµ std::thread([&](VideoPlayer *pointer) { pointer->decodeVideoThread(); }, this).detach(); } if (audioStream >= 0) { ///²éÕÒÒôƵ½âÂëÆ÷ aCodecCtx = pFormatCtx->streams[audioStream]->codec; aCodec = avcodec_find_decoder(aCodecCtx->codec_id); if (aCodec == NULL) { fprintf(stderr, "ACodec not found.\n"); audioStream = -1; } else { ///´ò¿ªÒôƵ½âÂëÆ÷ if (avcodec_open2(aCodecCtx, aCodec, nullptr) < 0) { fprintf(stderr, "Could not open audio codec.\n"); doOpenVideoFileFailed(); goto end; } ///½âÂëÒôƵÏà¹Ø aFrame = av_frame_alloc(); //ÖØ²ÉÑùÉèÖÃÑ¡Ïî-----------------------------------------------------------start aFrame_ReSample = nullptr; //frame->16bit 44100 PCM ͳһÒôƵ²ÉÑù¸ñʽÓë²ÉÑùÂÊ swrCtx = nullptr; //ÊäÈëµÄÉùµÀ²¼¾Ö int in_ch_layout; //Êä³öµÄÉùµÀ²¼¾Ö int out_ch_layout = av_get_default_channel_layout(audio_tgt_channels); ///AV_CH_LAYOUT_STEREO out_ch_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX; /// ÕâÀïÒôƵ²¥·ÅʹÓÃÁ˹̶¨µÄ²ÎÊý /// Ç¿ÖÆ½«ÒôÆµÖØ²ÉÑù³É44100 Ë«ÉùµÀ AV_SAMPLE_FMT_S16 /// SDL²¥·ÅÖÐÒ²ÊÇÓÃÁËͬÑùµÄ²¥·Å²ÎÊý //ÖØ²ÉÑùÉèÖÃÑ¡Ïî---------------- //ÊäÈëµÄ²ÉÑù¸ñʽ in_sample_fmt = aCodecCtx->sample_fmt; //Êä³öµÄ²ÉÑù¸ñʽ 16bit PCM out_sample_fmt = AV_SAMPLE_FMT_S16; //ÊäÈëµÄ²ÉÑùÂÊ in_sample_rate = aCodecCtx->sample_rate; //ÊäÈëµÄÉùµÀ²¼¾Ö in_ch_layout = aCodecCtx->channel_layout; //Êä³öµÄ²ÉÑùÂÊ out_sample_rate = 44100; //Êä³öµÄÉùµÀ²¼¾Ö audio_tgt_channels = 2; ///av_get_channel_layout_nb_channels(out_ch_layout); out_ch_layout = av_get_default_channel_layout(audio_tgt_channels); ///AV_CH_LAYOUT_STEREO out_ch_layout &= ~AV_CH_LAYOUT_STEREO_DOWNMIX; /// 2019-5-13Ìí¼Ó /// wav/wmv Îļþ»ñÈ¡µ½µÄaCodecCtx->channel_layoutΪ0»áµ¼ÖºóÃæµÄ³õʼ»¯Ê§°Ü£¬Òò´ËÕâÀïÐèÒª¼Ó¸öÅжϡ£ if (in_ch_layout <= 0) { in_ch_layout = av_get_default_channel_layout(aCodecCtx->channels); } swrCtx = swr_alloc_set_opts(nullptr, out_ch_layout, out_sample_fmt, out_sample_rate, in_ch_layout, in_sample_fmt, in_sample_rate, 0, nullptr); /** Open the resampler with the specified parameters. */ int ret = swr_init(swrCtx); if (ret < 0) { char buff[128]={0}; av_strerror(ret, buff, 128); fprintf(stderr, "Could not open resample context %s\n", buff); swr_free(&swrCtx); swrCtx = nullptr; doOpenVideoFileFailed(); goto end; } //´æ´¢pcmÊý¾Ý int out_linesize = out_sample_rate * audio_tgt_channels; // out_linesize = av_samples_get_buffer_size(NULL, audio_tgt_channels, av_get_bytes_per_sample(out_sample_fmt), out_sample_fmt, 1); out_linesize = AVCODEC_MAX_AUDIO_FRAME_SIZE; mAudioStream = pFormatCtx->streams[audioStream]; ///´ò¿ªSDL²¥·ÅÉùÒô int code = openSDL(); if (code == 0) { SDL_LockAudioDevice(mAudioID); SDL_PauseAudioDevice(mAudioID,0); SDL_UnlockAudioDevice(mAudioID); mIsAudioThreadFinished = false; } else { doOpenSdlFailed(code); } } } // av_dump_format(pFormatCtx, 0, file_path, 0); //Êä³öÊÓÆµÐÅÏ¢ mPlayerState = VideoPlayer_Playing; doPlayerStateChanged(VideoPlayer_Playing, mVideoStream != nullptr, mAudioStream != nullptr); mVideoStartTime = av_gettime(); fprintf(stderr, "%s mIsQuit=%d mIsPause=%d \n", __FUNCTION__, mIsQuit, mIsPause); while (1) { if (mIsQuit) { //Í£Ö¹²¥·ÅÁË break; } if (seek_req) { int stream_index = -1; int64_t seek_target = seek_pos; if (videoStream >= 0) stream_index = videoStream; else if (audioStream >= 0) stream_index = audioStream; AVRational aVRational = {1, AV_TIME_BASE}; if (stream_index >= 0) { seek_target = av_rescale_q(seek_target, aVRational, pFormatCtx->streams[stream_index]->time_base); } if (av_seek_frame(pFormatCtx, stream_index, seek_target, AVSEEK_FLAG_BACKWARD) < 0) { fprintf(stderr, "%s: error while seeking\n",pFormatCtx->filename); } else { if (audioStream >= 0) { AVPacket packet; av_new_packet(&packet, 10); strcpy((char*)packet.data,FLUSH_DATA); clearAudioQuene(); //Çå³ý¶ÓÁÐ inputAudioQuene(packet); //Íù¶ÓÁÐÖдæÈëÓÃÀ´Çå³ýµÄ°ü } if (videoStream >= 0) { AVPacket packet; av_new_packet(&packet, 10); strcpy((char*)packet.data,FLUSH_DATA); clearVideoQuene(); //Çå³ý¶ÓÁÐ inputVideoQuene(packet); //Íù¶ÓÁÐÖдæÈëÓÃÀ´Çå³ýµÄ°ü video_clock = 0; } mVideoStartTime = av_gettime() - seek_pos; mPauseStartTime = av_gettime(); } seek_req = 0; seek_time = seek_pos / 1000000.0; seek_flag_audio = 1; seek_flag_video = 1; if (mIsPause) { mIsNeedPause = true; mIsPause = false; } } //ÕâÀï×öÁ˸öÏÞÖÆ µ±¶ÓÁÐÀïÃæµÄÊý¾Ý³¬¹ýij¸ö´óСµÄʱºò ¾ÍÔÝÍ£¶ÁÈ¡ ·ÀÖ¹Ò»ÏÂ×ӾͰÑÊÓÆµ¶ÁÍêÁË£¬µ¼ÖµĿռä·ÖÅä²»×ã //Õâ¸öÖµ¿ÉÒÔÉÔ΢д´óһЩ if (mAudioPacktList.size() > MAX_AUDIO_SIZE || mVideoPacktList.size() > MAX_VIDEO_SIZE) { mSleep(10); continue; } if (mIsPause == true) { mSleep(10); continue; } AVPacket packet; if (av_read_frame(pFormatCtx, &packet) < 0) { mIsReadFinished = true; if (mIsQuit) { break; //½âÂëÏß³ÌÒ²Ö´ÐÐÍêÁË ¿ÉÒÔÍ˳öÁË } mSleep(10); continue; } if (packet.stream_index == videoStream) { inputVideoQuene(packet); //ÕâÀïÎÒÃǽ«Êý¾Ý´æÈë¶ÓÁÐ Òò´Ë²»µ÷Óà av_free_packet ÊÍ·Å } else if( packet.stream_index == audioStream ) { if (mIsAudioThreadFinished) { ///SDLûÓдò¿ª£¬ÔòÒôƵÊý¾ÝÖ±½ÓÊÍ·Å av_packet_unref(&packet); } else { inputAudioQuene(packet); //ÕâÀïÎÒÃǽ«Êý¾Ý´æÈë¶ÓÁÐ Òò´Ë²»µ÷Óà av_free_packet ÊÍ·Å } } else { // Free the packet that was allocated by av_read_frame av_packet_unref(&packet); } } ///Îļþ¶ÁÈ¡½áÊø Ìø³öÑ­»·µÄÇé¿ö ///µÈ´ý²¥·ÅÍê±Ï while (!mIsQuit) { mSleep(100); } end: clearAudioQuene(); clearVideoQuene(); if (mPlayerState != VideoPlayer_Stop) //²»ÊÇÍⲿµ÷ÓõÄstop ÊÇÕý³£²¥·Å½áÊø { stop(); } while((mVideoStream != nullptr && !mIsVideoThreadFinished) || (mAudioStream != nullptr && !mIsAudioThreadFinished)) { mSleep(10); } //È·±£ÊÓÆµÏ߳̽áÊøºó ÔÙÏú»Ù¶ÓÁÐ closeSDL(); if (swrCtx != nullptr) { swr_free(&swrCtx); swrCtx = nullptr; } if (aFrame != nullptr) { av_frame_free(&aFrame); aFrame = nullptr; } if (aFrame_ReSample != nullptr) { av_frame_free(&aFrame_ReSample); aFrame_ReSample = nullptr; } if (aCodecCtx != nullptr) { avcodec_close(aCodecCtx); aCodecCtx = nullptr; } if (pCodecCtx != nullptr) { avcodec_close(pCodecCtx); pCodecCtx = nullptr; } avformat_close_input(&pFormatCtx); avformat_free_context(pFormatCtx); SDL_Quit(); doPlayerStateChanged(VideoPlayer_Stop, mVideoStream != nullptr, mAudioStream != nullptr); mIsReadThreadFinished = true; fprintf(stderr, "%s finished \n", __FUNCTION__); } bool VideoPlayer::inputVideoQuene(const AVPacket &pkt) { if (av_dup_packet((AVPacket*)&pkt) < 0) { return false; } mConditon_Video->Lock(); mVideoPacktList.push_back(pkt); mConditon_Video->Signal(); mConditon_Video->Unlock(); return true; } void VideoPlayer::clearVideoQuene() { mConditon_Video->Lock(); for (AVPacket pkt : mVideoPacktList) { // av_free_packet(&pkt); av_packet_unref(&pkt); } mVideoPacktList.clear(); mConditon_Video->Unlock(); } bool VideoPlayer::inputAudioQuene(const AVPacket &pkt) { if (av_dup_packet((AVPacket*)&pkt) < 0) { return false; } mConditon_Audio->Lock(); mAudioPacktList.push_back(pkt); mConditon_Audio->Signal(); mConditon_Audio->Unlock(); return true; } void VideoPlayer::clearAudioQuene() { mConditon_Audio->Lock(); for (AVPacket pkt : mAudioPacktList) { // av_free_packet(&pkt); av_packet_unref(&pkt); } mAudioPacktList.clear(); mConditon_Audio->Unlock(); } ///µ±Ê¹ÓýçÃæÀà¼Ì³ÐÁ˱¾ÀàÖ®ºó£¬ÒÔϺ¯Êý²»»áÖ´ÐÐ ///´ò¿ªÎļþʧ°Ü void VideoPlayer::doOpenVideoFileFailed(const int &code) { fprintf(stderr, "%s \n", __FUNCTION__); if (mVideoPlayerCallBack != nullptr) { mVideoPlayerCallBack->onOpenVideoFileFailed(code); } } ///´ò¿ªsdlʧ°ÜµÄʱºò»Øµ÷´Ëº¯Êý void VideoPlayer::doOpenSdlFailed(const int &code) { fprintf(stderr, "%s \n", __FUNCTION__); if (mVideoPlayerCallBack != nullptr) { mVideoPlayerCallBack->onOpenSdlFailed(code); } } ///»ñÈ¡µ½ÊÓÆµÊ±³¤µÄʱºòµ÷Óô˺¯Êý void VideoPlayer::doTotalTimeChanged(const int64_t &uSec) { fprintf(stderr, "%s \n", __FUNCTION__); if (mVideoPlayerCallBack != nullptr) { mVideoPlayerCallBack->onTotalTimeChanged(uSec); } } ///²¥·ÅÆ÷״̬¸Ä±äµÄʱºò»Øµ÷´Ëº¯Êý void VideoPlayer::doPlayerStateChanged(const VideoPlayerState &state, const bool &hasVideo, const bool &hasAudio) { fprintf(stderr, "%s \n", __FUNCTION__); if (mVideoPlayerCallBack != nullptr) { mVideoPlayerCallBack->onPlayerStateChanged(state, hasVideo, hasAudio); } } ///ÏÔʾÊÓÆµÊý¾Ý£¬´Ëº¯Êý²»ÒË×öºÄʱ²Ù×÷£¬·ñÔò»áÓ°Ïì²¥·ÅµÄÁ÷³©ÐÔ¡£ void VideoPlayer::doDisplayVideo(const uint8_t *yuv420Buffer, const int &width, const int &height) { // fprintf(stderr, "%s \n", __FUNCTION__); if (mVideoPlayerCallBack != nullptr) { VideoFramePtr videoFrame = std::make_shared(); VideoFrame * ptr = videoFrame.get(); ptr->initBuffer(width, height); ptr->setYUVbuf(yuv420Buffer); mVideoPlayerCallBack->onDisplayVideo(videoFrame); } } void VideoPlayer::decodeVideoThread() { fprintf(stderr, "%s start \n", __FUNCTION__); mIsVideoThreadFinished = false; int videoWidth = 0; int videoHeight = 0; double video_pts = 0; //µ±Ç°ÊÓÆµµÄpts double audio_pts = 0; //ÒôƵpts ///½âÂëÊÓÆµÏà¹Ø AVFrame *pFrame = nullptr; AVFrame *pFrameYUV = nullptr; uint8_t *yuv420pBuffer = nullptr; //½âÂëºóµÄyuvÊý¾Ý struct SwsContext *imgConvertCtx = nullptr; //ÓÃÓÚ½âÂëºóµÄÊÓÆµ¸ñʽת»» AVCodecContext *pCodecCtx = mVideoStream->codec; //ÊÓÆµ½âÂëÆ÷ pFrame = av_frame_alloc(); while(1) { if (mIsQuit) { clearVideoQuene(); //Çå¿Õ¶ÓÁÐ break; } if (mIsPause == true) //ÅжÏÔÝÍ£ { mSleep(10); continue; } mConditon_Video->Lock(); if (mVideoPacktList.size() <= 0) { mConditon_Video->Unlock(); if (mIsReadFinished) { //¶ÓÁÐÀïÃæÃ»ÓÐÊý¾ÝÁËÇÒ¶ÁÈ¡Íê±ÏÁË break; } else { mSleep(1); //¶ÓÁÐÖ»ÊÇÔÝʱûÓÐÊý¾Ý¶øÒÑ continue; } } AVPacket pkt1 = mVideoPacktList.front(); mVideoPacktList.pop_front(); mConditon_Video->Unlock(); AVPacket *packet = &pkt1; //ÊÕµ½Õâ¸öÊý¾Ý ˵Ã÷¸Õ¸ÕÖ´ÐйýÌø×ª ÏÖÔÚÐèÒª°Ñ½âÂëÆ÷µÄÊý¾Ý Çå³ýһϠif(strcmp((char*)packet->data, FLUSH_DATA) == 0) { avcodec_flush_buffers(mVideoStream->codec); av_packet_unref(packet); continue; } if (avcodec_send_packet(pCodecCtx, packet) != 0) { qDebug("input AVPacket to decoder failed!\n"); av_packet_unref(packet); continue; } while (0 == avcodec_receive_frame(pCodecCtx, pFrame)) { if (packet->dts == AV_NOPTS_VALUE && pFrame->opaque&& *(uint64_t*) pFrame->opaque != AV_NOPTS_VALUE) { video_pts = *(uint64_t *) pFrame->opaque; } else if (packet->dts != AV_NOPTS_VALUE) { video_pts = packet->dts; } else { video_pts = 0; } video_pts *= av_q2d(mVideoStream->time_base); video_clock = video_pts; //OUTPUT("%s %f \n", __FUNCTION__, video_pts); if (seek_flag_video) { //·¢ÉúÁËÌø×ª ÔòÌø¹ý¹Ø¼üÖ¡µ½Ä¿µÄʱ¼äµÄÕ⼸֡ if (video_pts < seek_time) { av_packet_unref(packet); continue; } else { seek_flag_video = 0; } } ///ÒôÊÓÆµÍ¬²½£¬ÊµÏÖµÄÔ­Àí¾ÍÊÇ£¬ÅжÏÊÇ·ñµ½ÏÔʾ´Ë֡ͼÏñµÄʱ¼äÁË£¬Ã»µ½ÔòÐÝÃß5ms£¬È»ºó¼ÌÐøÅÐ¶Ï while(1) { if (mIsQuit) { break; } if (mAudioStream != NULL && !mIsAudioThreadFinished) { if (mIsReadFinished && mAudioPacktList.size() <= 0) {//¶ÁÈ¡ÍêÁË ÇÒÒôƵÊý¾ÝÒ²²¥·ÅÍêÁË ¾ÍÊ£ÏÂÊÓÆµÊý¾ÝÁË Ö±½ÓÏÔʾ³öÀ´ÁË ²»ÓÃͬ²½ÁË break; } ///ÓÐÒôƵµÄÇé¿öÏ£¬½«ÊÓÆµÍ¬²½µ½ÒôƵ ///¸úÒôƵµÄpts×ö¶Ô±È£¬±ÈÊÓÆµ¿ìÔò×öÑÓʱ audio_pts = audio_clock; } else { ///ûÓÐÒôƵµÄÇé¿öÏ£¬Ö±½Óͬ²½µ½ÍⲿʱÖÓ audio_pts = (av_gettime() - mVideoStartTime) / 1000000.0; audio_clock = audio_pts; } //OUTPUT("%s %f %f \n", __FUNCTION__, video_pts, audio_pts); //Ö÷ÒªÊÇ Ìø×ªµÄʱºò ÎÒÃǰÑvideo_clockÉèÖóÉ0ÁË //Òò´ËÕâÀïÐèÒª¸üÐÂvideo_pts //·ñÔòµ±´ÓºóÃæÌø×ªµ½Ç°ÃæµÄʱºò »á¿¨ÔÚÕâÀï video_pts = video_clock; if (video_pts <= audio_pts) break; int delayTime = (video_pts - audio_pts) * 1000; delayTime = delayTime > 5 ? 5:delayTime; if (!mIsNeedPause) { mSleep(delayTime); } } if (pCodecCtx->width != videoWidth || pCodecCtx->height != videoHeight) { videoWidth = pFrame->width; videoHeight = pFrame->height; if (pFrameYUV != nullptr) { av_free(pFrameYUV); } if (yuv420pBuffer != nullptr) { av_free(yuv420pBuffer); } if (imgConvertCtx != nullptr) { sws_freeContext(imgConvertCtx); } pFrameYUV = av_frame_alloc(); int yuvSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1); //°´1×Ö½Ú½øÐÐÄÚ´æ¶ÔÆë,µÃµ½µÄÄÚ´æ´óС×î½Ó½üʵ¼Ê´óС // int yuvSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 0); //°´0×Ö½Ú½øÐÐÄÚ´æ¶ÔÆë£¬µÃµ½µÄÄÚ´æ´óСÊÇ0 // int yuvSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 4); //°´4×Ö½Ú½øÐÐÄÚ´æ¶ÔÆë£¬µÃµ½µÄÄÚ´æ´óСÉÔ΢´óһЩ unsigned int numBytes = static_cast(yuvSize); yuv420pBuffer = static_cast(av_malloc(numBytes * sizeof(uint8_t))); av_image_fill_arrays(pFrameYUV->data, pFrameYUV->linesize, yuv420pBuffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height, 1); ///ÓÉÓÚ½âÂëºóµÄÊý¾Ý²»Ò»¶¨¶¼ÊÇyuv420p£¬Òò´ËÐèÒª½«½âÂëºóµÄÊý¾Ýͳһת»»³ÉYUV420P imgConvertCtx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL); } sws_scale(imgConvertCtx, (uint8_t const * const *) pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize); // FILE *fp_yuv = fopen("./frame.yuv", "wb"); // fwrite(yuv420pBuffer, 1, pCodecCtx->width * pCodecCtx->height * 3 /2, fp_yuv); // fclose(fp_yuv); doDisplayVideo(yuv420pBuffer, pCodecCtx->width, pCodecCtx->height); if (mIsNeedPause) { mIsPause = true; mIsNeedPause = false; } } av_packet_unref(packet); } av_free(pFrame); if (pFrameYUV != nullptr) { av_free(pFrameYUV); } if (yuv420pBuffer != nullptr) { av_free(yuv420pBuffer); } if (imgConvertCtx != nullptr) { sws_freeContext(imgConvertCtx); } if (!mIsQuit) { mIsQuit = true; } mIsVideoThreadFinished = true; fprintf(stderr, "%s finished \n", __FUNCTION__); return; } void VideoPlayer::sdlAudioCallBackFunc(void *userdata, Uint8 *stream, int len) { VideoPlayer *player = (VideoPlayer*)userdata; player->sdlAudioCallBack(stream, len); } void VideoPlayer::sdlAudioCallBack(Uint8 *stream, int len) { int len1, audio_data_size; /* lenÊÇÓÉSDL´«ÈëµÄSDL»º³åÇøµÄ´óС£¬Èç¹ûÕâ¸ö»º³åδÂú£¬ÎÒÃǾÍÒ»Ö±ÍùÀïÌî³äÊý¾Ý */ while (len > 0) { /* audio_buf_index ºÍ audio_buf_size ±êʾÎÒÃÇ×Ô¼ºÓÃÀ´·ÅÖýâÂë³öÀ´µÄÊý¾ÝµÄ»º³åÇø£¬*/ /* ÕâЩÊý¾Ý´ýcopyµ½SDL»º³åÇø£¬ µ±audio_buf_index >= audio_buf_sizeµÄʱºòÒâζ×ÅÎÒ*/ /* ÃǵĻº³åΪ¿Õ£¬Ã»ÓÐÊý¾Ý¿É¹©copy£¬ÕâʱºòÐèÒªµ÷ÓÃaudio_decode_frameÀ´½âÂë³ö¸ü /* ¶àµÄèåÊý¾Ý */ if (audio_buf_index >= audio_buf_size) { audio_data_size = decodeAudioFrame(); /* audio_data_size < 0 ±êʾûÄܽâÂë³öÊý¾Ý£¬ÎÒÃÇĬÈϲ¥·Å¾²Òô */ if (audio_data_size <= 0) { /* silence */ audio_buf_size = 1024; /* ÇåÁ㣬¾²Òô */ memset(audio_buf, 0, audio_buf_size); } else { audio_buf_size = audio_data_size; } audio_buf_index = 0; } /* ²é¿´stream¿ÉÓÿռ䣬¾ö¶¨Ò»´Îcopy¶àÉÙÊý¾Ý£¬Ê£ÏµÄÏ´μÌÐøcopy */ len1 = audio_buf_size - audio_buf_index; if (len1 > len) { len1 = len; } if (audio_buf == NULL) return; if (mIsMute || mIsNeedPause) //¾²Òô »òÕß ÊÇÔÚÔÝÍ£µÄʱºòÌø×ªÁË { memset(audio_buf + audio_buf_index, 0, len1); } else { PcmVolumeControl::RaiseVolume((char*)audio_buf + audio_buf_index, len1, 1, mVolume); } memcpy(stream, (uint8_t *)audio_buf + audio_buf_index, len1); // SDL_memset(stream, 0x0, len);// make sure this is silence. // SDL_MixAudio(stream, (uint8_t *) audio_buf + audio_buf_index, len1, SDL_MIX_MAXVOLUME); // SDL_MixAudio(stream, (uint8_t * )is->audio_buf + is->audio_buf_index, len1, 50); // SDL_MixAudioFormat(stream, (uint8_t * )is->audio_buf + is->audio_buf_index, AUDIO_S16SYS, len1, 50); len -= len1; stream += len1; audio_buf_index += len1; } } int VideoPlayer::decodeAudioFrame(bool isBlock) { int audioBufferSize = 0; while(1) { if (mIsQuit) { mIsAudioThreadFinished = true; clearAudioQuene(); //Çå¿Õ¶ÓÁÐ break; } if (mIsPause == true) //ÅжÏÔÝÍ£ { break; } mConditon_Audio->Lock(); if (mAudioPacktList.size() <= 0) { if (isBlock) { mConditon_Audio->Wait(); } else { mConditon_Audio->Unlock(); break; } } AVPacket packet = mAudioPacktList.front(); mAudioPacktList.pop_front(); qDebug()<<__FUNCTION__<Unlock(); AVPacket *pkt = &packet; /* if update, update the audio clock w/pts */ if (pkt->pts != AV_NOPTS_VALUE) { audio_clock = av_q2d(mAudioStream->time_base) * pkt->pts; } //ÊÕµ½Õâ¸öÊý¾Ý ˵Ã÷¸Õ¸ÕÖ´ÐйýÌø×ª ÏÖÔÚÐèÒª°Ñ½âÂëÆ÷µÄÊý¾Ý Çå³ýһϠif(strcmp((char*)pkt->data,FLUSH_DATA) == 0) { avcodec_flush_buffers(mAudioStream->codec); av_packet_unref(pkt); continue; } if (seek_flag_audio) { //·¢ÉúÁËÌø×ª ÔòÌø¹ý¹Ø¼üÖ¡µ½Ä¿µÄʱ¼äµÄÕ⼸֡ if (audio_clock < seek_time) { continue; } else { seek_flag_audio = 0; } } //½âÂëAVPacket->AVFrame int got_frame = 0; int size = avcodec_decode_audio4(aCodecCtx, aFrame, &got_frame, &packet); //±£´æÖزÉÑù֮ǰµÄÒ»¸öÉùµÀµÄÊý¾Ý·½·¨ //size_t unpadded_linesize = aFrame->nb_samples * av_get_bytes_per_sample((AVSampleFormat) aFrame->format); //static FILE * fp = fopen("out.pcm", "wb"); //fwrite(aFrame->extended_data[0], 1, unpadded_linesize, fp); av_packet_unref(&packet); if (got_frame) { /// ffmpeg½âÂëÖ®ºóµÃµ½µÄÒôƵÊý¾Ý²»ÊÇSDLÏëÒªµÄ£¬ /// Òò´ËÕâÀïÐèÒªÖØ²ÉÑù³É44100 Ë«ÉùµÀ AV_SAMPLE_FMT_S16 if (aFrame_ReSample == NULL) { aFrame_ReSample = av_frame_alloc(); } if (aFrame_ReSample->nb_samples != aFrame->nb_samples) { aFrame_ReSample->nb_samples = av_rescale_rnd(swr_get_delay(swrCtx, out_sample_rate) + aFrame->nb_samples, out_sample_rate, in_sample_rate, AV_ROUND_UP); av_samples_fill_arrays(aFrame_ReSample->data, aFrame_ReSample->linesize, audio_buf, audio_tgt_channels, aFrame_ReSample->nb_samples, out_sample_fmt, 0); } int len2 = swr_convert(swrCtx, aFrame_ReSample->data, aFrame_ReSample->nb_samples, (const uint8_t**)aFrame->data, aFrame->nb_samples); int resampled_data_size = len2 * audio_tgt_channels * av_get_bytes_per_sample(out_sample_fmt); audioBufferSize = resampled_data_size; break; } } return audioBufferSize; }