ffmpeg+D3D实现的MFC音视频播放器,支持录像、截图、音视频播放、码流信息 ...

打印 上一主题 下一主题

主题 833|帖子 833|积分 2499

一、简介

    本播放器是在vs2019下开发,通过ffmpeg实现拉流解码功能,通过D3D实现视频的渲染功能。截图功能采用libjpeg实现,可以截取jpg图片,图片的默认保存路径是在C:\MYRecPath中。录像功能采用封装好的类Mp4Record实现,在Mp4Record类中主要还是采用ffmpeg的相关函数方法进行mp4视频的录制。音频的播放采用DirectSound实现,将ffmpeg解码后的音频数据存储到DirectSound的buffer中,再调用DirectSound的play实现对音频的播放功能。码流信息的表现,通过D3D的文本绘制实现。本播放器提供源码下载,直接下载请点击末了的下载链接。
二、界面展示


三、相关代码

开始播放
  1. int CVideoPlayer::StartPlay(const char* sUrl)
  2. {
  3.     m_bStop = false;
  4.     m_nVideoIndex = -1;
  5.     m_nAudioIndex = -1;
  6.     int i = 0, res = 0,  nValue = 0;
  7.     char buf[64] = { 0 };
  8.     m_bPlaying = false;
  9.     AVStream* in_stream;
  10.    
  11.     _snprintf_s(m_sConnectUrl, sizeof(m_sConnectUrl), sizeof(m_sConnectUrl) - 1, "%s", sUrl);
  12.     //av_register_all();
  13.     avformat_network_init();
  14.     AVDictionary* optionsDict = nullptr;
  15.     av_dict_set(&optionsDict, "rtsp_transport", "tcp", 0);
  16.     av_dict_set(&optionsDict, "stimeout", "5000000", 0);
  17.     av_dict_set(&optionsDict, "buffer_size", "8192000", 0);
  18.     av_dict_set(&optionsDict, "recv_buffer_size", "8192000", 0);
  19.     m_lastReadPacktTime = av_gettime();
  20.     m_pAVFmtCxt = avformat_alloc_context();
  21.     m_pAVFmtCxt->interrupt_callback.opaque = this;
  22.     m_pAVFmtCxt->interrupt_callback.callback = decodeInterruptCb;
  23.     res = avformat_open_input(&m_pAVFmtCxt, m_sConnectUrl, NULL, &optionsDict);
  24.     if (res < 0)
  25.     {
  26.         myprint("avformat_open_input fail: %d", res);
  27.         return -1;
  28.     }
  29.    
  30.     if (!m_pAVFmtCxt)
  31.     {
  32.         return -1;
  33.     }
  34.     m_pAVFmtCxt->probesize = 100 * 1024;   
  35.     m_pAVFmtCxt->max_analyze_duration = 1 * AV_TIME_BASE;
  36.     res = avformat_find_stream_info(m_pAVFmtCxt, NULL);
  37.     if (res < 0)
  38.     {
  39.         myprint("error %x in avformat_find_stream_info\n", res);
  40.         return -1;
  41.     }
  42.     av_dump_format(m_pAVFmtCxt, 0, m_sConnectUrl, 0);
  43.     for (i = 0; i < m_pAVFmtCxt->nb_streams; i++)
  44.     {
  45.         if (m_pAVFmtCxt->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
  46.         {
  47.             m_nVideoIndex = i;
  48.         }
  49.         else if (m_pAVFmtCxt->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
  50.             m_nAudioIndex = i;
  51.         }
  52.         myprint("m_pAVFmtCxt->streams[i]->codec->codec_type:%d", m_pAVFmtCxt->streams[i]->codecpar->codec_type);
  53.     }
  54.     //videoindex not find
  55.     if (m_nVideoIndex == -1)
  56.     {
  57.         myprint("can't find video stream.");
  58.         return -1;
  59.     }
  60.     m_pCodec = avcodec_find_decoder(m_pAVFmtCxt->streams[m_nVideoIndex]->codecpar->codec_id);
  61.     if (!m_pCodec)
  62.     {
  63.         myprint("video decoder not found\n");
  64.         return -1;
  65.     }
  66.     if (m_bSupportAudio && m_nAudioIndex != -1)
  67.     {
  68.         myprint("start audio decoder \n");
  69.         if (!m_pAudioCodecCxt)
  70.             m_pAudioCodecCxt = avcodec_alloc_context3(NULL);
  71.         auto pAudioCodecpar = m_pAVFmtCxt->streams[m_nAudioIndex]->codecpar;
  72.         avcodec_parameters_to_context(m_pAudioCodecCxt, pAudioCodecpar);
  73.         m_pAudioCodec = avcodec_find_decoder(pAudioCodecpar->codec_id);
  74.         if (nullptr == m_pAudioCodec || nullptr == m_pAudioCodecCxt)
  75.         {
  76.             myprint("audio decoder not found\n");
  77.             return -1;
  78.         }
  79.         m_pSwrContext = swr_alloc_set_opts(0,                                 
  80.             av_get_default_channel_layout(m_channels_play),
  81.             AV_SAMPLE_FMT_S16,                        
  82.             m_nSampleRate,                     
  83.             av_get_default_channel_layout(m_pAudioCodecCxt->channels),
  84.             m_pAudioCodecCxt->sample_fmt,      
  85.             m_pAudioCodecCxt->sample_rate,      
  86.             0,
  87.             0);
  88.         auto ret = swr_init(m_pSwrContext);
  89.         if (ret < 0)
  90.         {
  91.             myprint("Failed to swr_init(pSwrContext);");
  92.             return -1;
  93.         }
  94.         if (InitDirectSound() == FALSE)
  95.             m_bSupportAudio = false;
  96.     }
  97.     m_CodecId = m_pCodec->id;
  98.     if(!m_pCodecCxt)
  99.         m_pCodecCxt = avcodec_alloc_context3(NULL);
  100.     avcodec_parameters_to_context(m_pCodecCxt, m_pAVFmtCxt->streams[m_nVideoIndex]->codecpar);
  101.     if (m_pCodecCxt)
  102.     {
  103.         if (m_pCodecCxt->width == 0 || m_pCodecCxt->height == 0)
  104.         {
  105.             myprint("m_pCodecCxt->width:%d, m_pCodecCxt->height:%d", m_pCodecCxt->width, m_pCodecCxt->height);
  106.             return -1;
  107.         }
  108.     }
  109.     else
  110.         return -1;
  111.     AVCodecContext* temp_codecctx = m_pCodecCxt;
  112.     memcpy(temp_codecctx, m_pCodecCxt, sizeof(m_pCodecCxt));
  113.     if (m_pCodecCxt->codec_type == AVMEDIA_TYPE_VIDEO)
  114.     {
  115.         myprint("Soft Solution");
  116.         avcodec_close(m_pCodecCxt);
  117.         m_pCodecCxt = temp_codecctx;
  118.         m_pCodecCxt->thread_count = 4;
  119.         if (m_Dxva2D3DRender.InitD3DRender(m_showWnd, m_pCodecCxt->width, m_pCodecCxt->height) == false)
  120.         {
  121.             myprint("InitD3DRender fail");
  122.         }
  123.         m_pOutBuffer = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, m_pCodecCxt->width, m_pCodecCxt->height, 1));
  124.         if (nullptr == m_pOutBuffer)
  125.             return -1;
  126.         av_image_fill_arrays(m_pFrameBGR->data, m_pFrameBGR->linesize, m_pOutBuffer, AV_PIX_FMT_YUV420P, m_pCodecCxt->width, m_pCodecCxt->height, 1); //填充AVFrame数据缓冲
  127.         m_pImgConvertCtx = sws_getContext(m_pCodecCxt->width, m_pCodecCxt->height, m_pCodecCxt->pix_fmt, m_pCodecCxt->width, m_pCodecCxt->height, AV_PIX_FMT_YUV420P, SWS_FAST_BILINEAR, NULL, NULL, NULL);
  128.         if (nullptr == m_pImgConvertCtx)
  129.             return -1;
  130.       
  131.         m_nActualWidth = m_pCodecCxt->width;
  132.         m_nActualHeight = m_pCodecCxt->height;
  133.         res = avcodec_open2(m_pCodecCxt, m_pCodec, NULL);
  134.         if (res < 0)
  135.         {
  136.             myprint("avcodec_open2 video fail  error:%x", res);
  137.             return -1;
  138.         }
  139.     }
  140.     if (m_bSupportAudio && m_pAudioCodecCxt)
  141.     {
  142.         if (m_pAudioCodecCxt->codec_type == AVMEDIA_TYPE_AUDIO)
  143.         {
  144.             res = avcodec_open2(m_pAudioCodecCxt, m_pAudioCodec, NULL);
  145.             if (res < 0)
  146.             {
  147.                 myprint("avcodec_open2 audio fail  error:%x", res);
  148.                 avcodec_close(m_pAudioCodecCxt);
  149.                 return -1;
  150.             }
  151.             myprint("===Audio Message===");
  152.             myprint(" bit_rate = %d ", m_pAudioCodecCxt->bit_rate);
  153.             myprint(" sample_rate = %d ", m_pAudioCodecCxt->sample_rate);
  154.             myprint(" channels = %d ", m_pAudioCodecCxt->channels);
  155.             myprint(" code_name = %s ", m_pAudioCodecCxt->codec->name);
  156.             myprint(" block_align = %d ", m_pAudioCodecCxt->block_align);
  157.         }
  158.     }
  159.     m_pDecodeThread = (my_thread_t*)my_malloc(sizeof(my_thread_t));
  160.     if (nullptr != m_pDecodeThread)
  161.     {
  162.         m_bDecodeThreadRun = true;
  163.         res = my_thread_create(m_pDecodeThread, ThreadDecode, this);
  164.         if (res == -1)
  165.         {
  166.             myprint("my_thread_create ThreadDecode failed  res:%x", res);
  167.             return -1;
  168.         }
  169.     }
  170.     return 0;
  171. }
复制代码
停止播放
  1. void CVideoPlayer::StopPlay()
  2. {
  3.     m_bPlaying = false;
  4.     m_CaptureAudio.SetGrabAudioFrames(FALSE, NULL);
  5.     m_CaptureAudio.Close();
  6.     m_bStopAudio = true;
  7.     while (!m_AudioPlayQue.empty())
  8.     {
  9.         m_AudioPlayQue.pop();
  10.     }
  11.     while (!m_AudioTalkQue.empty())
  12.     {
  13.         EnterCriticalSection(&m_talklock);
  14.         m_AudioTalkQue.pop();
  15.         LeaveCriticalSection(&m_talklock);
  16.     }
  17.     m_bDecodeThreadRun = false;
  18.     if (m_pDecodeThread)
  19.     {
  20.         my_thread_join(m_pDecodeThread);
  21.         my_free(m_pDecodeThread);
  22.         m_pDecodeThread = nullptr;
  23.     }
  24.     if (m_pAudioPlayThread) {
  25.         SetEvent(m_event);
  26.         if (m_pAudioPlayThread->handle) {
  27.             my_thread_join(m_pAudioPlayThread);
  28.             m_pAudioPlayThread->handle = nullptr;
  29.         }
  30.     }
  31.     if (m_pDSBuffer8)
  32.     {
  33.         m_pDSBuffer8->Stop();
  34.         m_pDSBuffer8->Restore();
  35.     }
  36.     m_Dxva2D3DRender.UnitD3DRender();
  37.     if (m_pCodecCxt)
  38.     {
  39.         avcodec_close(m_pCodecCxt);
  40.     }
  41.     if (m_pAudioCodecCxt)
  42.     {
  43.         avcodec_close(m_pAudioCodecCxt);
  44.     }
  45.     if (m_pSwrContext)
  46.     {
  47.         swr_free(&m_pSwrContext);
  48.         m_pSwrContext = nullptr;
  49.     }
  50.     if (m_pAVFmtCxt) {
  51.         avformat_close_input(&m_pAVFmtCxt);
  52.         avformat_free_context(m_pAVFmtCxt);
  53.         m_pAVFmtCxt = nullptr;
  54.     }
  55. }
复制代码
解码线程
  1. void CVideoPlayer::DecodeAndShow()
  2. {
  3.     if (m_pAVFmtCxt == nullptr || m_pCodecCxt == nullptr)
  4.         return;
  5.     AVPacket pkt = { 0 };
  6.     m_bPlaying = true;
  7.     uint8_t* pBuffer;
  8.     bool bEnoughSpace = true;
  9.     int nTimeCnt = 0;
  10.     int res = 0;
  11.     struct SwsContext* img_convert_ctx = nullptr;
  12.     int nRectDrawWait = 0;
  13.     bool bRecordLastIFrame = false;
  14.     int num_av_read_frame_err = 0;
  15.     int num_stream_index_err = 0;
  16.     uint8_t * outData[2] = {0};
  17.     outData[0] = (uint8_t*)av_malloc(1152 * 8);
  18.     outData[1] = (uint8_t*)av_malloc(1152 * 8);
  19.     uint8_t* pktdata;
  20.     int pktsize;
  21.     int len = 0;
  22.     bool bPushAudioToQueue = false;
  23.     m_bStopAudio = false;
  24.     CRect ShowRect;
  25.     AVFrame* pAvFrame = av_frame_alloc();
  26.     if (nullptr == pAvFrame)
  27.         return;
  28.     AVFrame* pFrameRGB = av_frame_alloc();
  29.     if (nullptr == pFrameRGB)
  30.         return;
  31.     int numBytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, m_pCodecCxt->width, m_pCodecCxt->height, 1);
  32.     pBuffer = (uint8_t*)av_malloc(numBytes);
  33.     if (nullptr == pBuffer)
  34.         return;
  35.     av_image_fill_arrays(pFrameRGB->data,pFrameRGB->linesize, pBuffer, AV_PIX_FMT_RGB24, m_pCodecCxt->width, m_pCodecCxt->height, 1);
  36.     img_convert_ctx = sws_getCachedContext(img_convert_ctx, m_pCodecCxt->width, m_pCodecCxt->height,
  37.         m_pCodecCxt->pix_fmt, m_pCodecCxt->width, m_pCodecCxt->height, AV_PIX_FMT_RGB24, SWS_FAST_BILINEAR/*SWS_BICUBIC*/, NULL, NULL, NULL);
  38.     //Audio
  39.     if (m_bSupportAudio && m_pAudioPlayThread)
  40.     {
  41.         res = my_thread_create(m_pAudioPlayThread, ThreadAudioPlay, this);
  42.         if (res < 0)
  43.             myprint("my_thread_create ThreadAudioPlay fail");
  44.     }
  45.     while (m_bDecodeThreadRun && !m_bQuit)
  46.     {
  47.         if (m_bPause)
  48.         {
  49.             Sleep(100);
  50.             continue;
  51.         }
  52.         {
  53.             if (m_bReconnect)
  54.             {
  55.                 myprint("bReConnect = true, break");
  56.                 break;
  57.             }
  58.         }
  59.         m_lastReadPacktTime = av_gettime();
  60.         if (av_read_frame(m_pAVFmtCxt, &pkt) >= 0)
  61.         {
  62.             num_av_read_frame_err = 0;
  63.             if (pkt.stream_index == m_nVideoIndex || pkt.stream_index == m_nAudioIndex)
  64.             {
  65.                 if (m_bRecord)//Record
  66.                 {
  67.                     if (nTimeCnt != 0 || (!bRecordLastIFrame && pkt.flags == AV_PKT_FLAG_KEY)) {
  68.                         if (m_sRecPath[0] != '\0' && nTimeCnt++ % 200 == 0)
  69.                         {
  70.                             bEnoughSpace = CheckRemainSpace(m_sRecPath);
  71.                             if (bEnoughSpace == true)
  72.                             {
  73.                                 myprint("bEnoughSpace = true");
  74.                             }
  75.                             else
  76.                                 myprint("bEnoughSpace = false");
  77.                         }
  78.                         m_nRecordCurrentTime = time(NULL);
  79.                         if ((m_nRecordCurrentTime - m_nRecordStartTime) >= (m_nRecordTime * 60))
  80.                         {
  81.                             myprint("Record Finsh!");
  82.                             stopRecord();
  83.                         }
  84.                         else if (bEnoughSpace == false)
  85.                         {
  86.                             myprint("bEnoughSpace == false");
  87.                             stopRecord();
  88.                         }
  89.                         else
  90.                         {
  91.                             AVPacket* pPkt = av_packet_clone(&pkt);
  92.                             m_mp4Recorder.saveOneFrame(*pPkt, m_CodecId);
  93.                             av_packet_free(&pPkt);
  94.                         }
  95.                     }
  96.                     bRecordLastIFrame = pkt.flags == AV_PKT_FLAG_KEY;
  97.                 }
  98.                 else
  99.                     nTimeCnt = 0;
  100.             }
  101.             
  102.             if (pkt.stream_index == m_nVideoIndex)
  103.             {
  104.                 num_stream_index_err = 0;
  105.                 nTimeCnt = 0;
  106.                 if (pkt.flags == 1)
  107.                     bPushAudioToQueue = true;
  108.                 if (nullptr == m_pCodecCxt || nullptr == pAvFrame) {
  109.                     myprint("m_pCodecCxt == NULL || pAvFrame == NULL");
  110.                     break;
  111.                 }
  112.                 int gotvframe = 0;
  113.                 auto sd_ret = avcodec_send_packet(m_pCodecCxt, &pkt);
  114.                 if (sd_ret != 0 && sd_ret != AVERROR(EAGAIN)) {
  115.                     myprint("avcodec_send_packet err, rt=%d", sd_ret);
  116.                     enableReConnect();
  117.                 }
  118.                 else {
  119.                     while (gotvframe == 0 && !m_bQuit) {
  120.                         gotvframe = avcodec_receive_frame(m_pCodecCxt, pAvFrame);
  121.                         if (gotvframe == 0)
  122.                         {
  123.                             try
  124.                             {
  125.                                 GetShowRectSize(&ShowRect);
  126.                             }
  127.                             catch (const std::exception&)
  128.                             {
  129.                                 myprint("GetClientRect throw, error");
  130.                                 break;
  131.                             }
  132.                             m_nCurPKSize = pkt.size;   
  133.                             SetStreamInfoToD3d();
  134.                             if (pAvFrame->width != m_nActualWidth || pAvFrame->height != m_nActualHeight)
  135.                             {
  136.                                 myprint("video size change reconnect...");
  137.                                 enableReConnect();
  138.                                 m_nActualWidth = pAvFrame->width;
  139.                                 m_nActualHeight = pAvFrame->height;
  140.                                 av_packet_unref(&pkt);
  141.                                 continue;
  142.                             }
  143.                             if (m_pImgConvertCtx && m_pFrameBGR && m_pOutBuffer && pAvFrame)
  144.                             {
  145.                                 sws_scale(m_pImgConvertCtx, (const uint8_t* const*)pAvFrame->data, pAvFrame->linesize, 0,
  146.                                     m_pCodecCxt->height, m_pFrameBGR->data, m_pFrameBGR->linesize);
  147.                                 {                                    
  148.                                     try
  149.                                     {
  150.                                         int re = 5;
  151.                                         for (int i = 0; m_bPlaying && re == 5 && i < 10; ++i) {     // LockRect失败时重复尝试,最多10次
  152.                                             re = m_Dxva2D3DRender.D3DSoftDisplayFrame(m_pOutBuffer, pAvFrame->width, pAvFrame->height, ShowRect);
  153.                                             Sleep(1);
  154.                                         }
  155.                                     }
  156.                                     catch (int re)
  157.                                     {
  158.                                         myprint("m_Dxva2D3DRender.InitD3DRender again");
  159.                                         if (m_Dxva2D3DRender.InitD3DRender(m_showWnd, m_pCodecCxt->width, m_pCodecCxt->height) == false)
  160.                                         {
  161.                                             myprint("m_Dxva2D3DRender.InitD3DRender again fail");
  162.                                             av_packet_unref(&pkt);
  163.                                             continue;
  164.                                         }
  165.                                     }
  166.                                 }                                
  167.                             }
  168.                             if (m_bCapture /*&& pkt.flags == 1*/ && img_convert_ctx)
  169.                             {
  170.                                 sws_scale(img_convert_ctx, (const uint8_t* const*)pAvFrame->data,
  171.                                          pAvFrame->linesize, 0, m_pCodecCxt->height,
  172.                                     pFrameRGB->data, pFrameRGB->linesize);
  173.                                 SaveIFrameImage(pFrameRGB->data[0], m_pCodecCxt->width, m_pCodecCxt->height);
  174.                                 m_bCapture = false;
  175.                             }
  176.                            
  177.                         }
  178.                     }
  179.                 }
  180.             }
  181.             else if (pkt.stream_index == m_nAudioIndex)
  182.             {
  183.                 num_stream_index_err = 0;
  184.                 if (m_bSupportAudio) {
  185.                     pktdata = pkt.data;
  186.                     pktsize = pkt.size;
  187.                     if (pktsize > 0)
  188.                     {
  189.                         int gotframe = 0;
  190.                         if (nullptr == m_pAudioCodecCxt || nullptr == pAvFrame) {
  191.                             myprint("m_pAudioCodecCxt == NULL || pAvFrame == NULL");
  192.                             break;
  193.                         }
  194.                         len = avcodec_send_packet(m_pAudioCodecCxt, &pkt);
  195.                         if (len != 0 && len != AVERROR(EAGAIN))
  196.                         {
  197.                             pktsize = 0;
  198.                             myprint("avcodec_send_packet len < 0");
  199.                             break;
  200.                         }
  201.                         auto data_size = av_get_bytes_per_sample(m_pAudioCodecCxt->sample_fmt);
  202.                         if (data_size < 0) {
  203.                             myprint("Failed to calculate data size\n");
  204.                             break;
  205.                         }
  206.                         while (gotframe == 0 && !m_bQuit) {
  207.                             gotframe = avcodec_receive_frame(m_pAudioCodecCxt, pAvFrame);
  208.                             if (!gotframe)
  209.                             {
  210.                                 if (bPushAudioToQueue == true && m_bEnableAudio && !m_bStopAudio)
  211.                                 {
  212.                                     audio_frame_t audioFrame;
  213.                                     numBytes = av_get_bytes_per_sample(AV_SAMPLE_FMT_S16);
  214.                                     auto dstNbSamples = av_rescale_rnd(pAvFrame->nb_samples,
  215.                                         m_src_sample_rate,
  216.                                         pAvFrame->sample_rate,
  217.                                         AV_ROUND_ZERO);
  218.                                       
  219.                                     int data_size = 0;
  220.                                     try
  221.                                     {
  222.                                         auto nb = swr_convert(m_pSwrContext,
  223.                                             (uint8_t**)outData,
  224.                                             dstNbSamples,
  225.                                             (const uint8_t**)pAvFrame->data,
  226.                                             pAvFrame->nb_samples);
  227.                                         data_size = av_samples_get_buffer_size(nullptr, m_channels_play, nb, AV_SAMPLE_FMT_S16, 1);
  228.                                     }
  229.                                     catch (const std::exception&)
  230.                                     {
  231.                                         m_bSupportAudio = false;
  232.                                         myprint("swr_convert throw err, set m_bSupportAudio false");
  233.                                         continue;
  234.                                     }
  235.                                     
  236.                                     int copy_size = 0;
  237.                                     int copy_ptr = 0;                              
  238.                                     for (int isub = data_size; isub > 0; isub -= copy_size) {
  239.                                         if (isub > m_audio_buffer_notify_size) {
  240.                                             copy_size = m_audio_buffer_notify_size;
  241.                                             copy_ptr = data_size - isub;
  242.                                         }
  243.                                         else
  244.                                             copy_size = isub;
  245.                                         audioFrame.data_size = copy_size;
  246.                                         memcpy(audioFrame.data, outData[0] + copy_ptr, copy_size);
  247.                                         EnterCriticalSection(&m_lock);
  248.                                         m_AudioPlayQue.push(audioFrame);
  249.                                         LeaveCriticalSection(&m_lock);
  250.                                     }
  251.                                 }
  252.                             }
  253.                         }
  254.                     }
  255.                 }
  256.             }
  257.             else if (++num_stream_index_err > 20) {
  258.                 myprint("pkt.stream_index unfind, %d",pkt.stream_index);
  259.                 enableReConnect();
  260.             }
  261.             av_packet_unref(&pkt);
  262.         }
  263.         else {
  264.             if (++num_av_read_frame_err > 10) {
  265.                 myprint("num_av_read_frame_err is more than 10");
  266.                 enableReConnect();
  267.             }
  268.         }
  269.     }
  270.     if (m_bDecodeThreadRun) {
  271.         myprint("m_bDecodeThreadRun is true");
  272.         enableReConnect();
  273.     }
  274.     if (pAvFrame)
  275.         av_free(pAvFrame);
  276.     if (pFrameRGB)
  277.         av_free(pFrameRGB);
  278.     if (pBuffer)
  279.         av_free(pBuffer);
  280.     if (img_convert_ctx)
  281.         sws_freeContext(img_convert_ctx);
  282.     if (outData[0] && outData[1])
  283.     {
  284.         av_free(outData[0]);
  285.         av_free(outData[1]);
  286.         outData[0] = 0;
  287.         outData[1] = 0;
  288.     }
  289. }
复制代码
四、相关下载

链接: 可实行步伐下载
链接: 源码下载

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表