FFmpeg_3.2.4+SDL_2.0.5学习(1)音视频解码帧及显示/播放数据

  1. int OpenAVFile(const char* szFileName)  
  2. {  
  3.     char errbuf[256] = { 0 };  
  4.     int iRes = 0;  
  5.     int vindex = -1;  
  6.     AVFormatContext* pFmtCtx = NULL;  
  7.     AVCodecContext* vCodecCtx = NULL;  
  8.     AVCodec* vCodec = NULL;  
  9.     AVPacket* pkt = NULL;  
  10.     AVFrame* pfe = NULL;  
  11.     AVFrame* YUV = NULL;  
  12.     uint8_t* buf = NULL;  
  13.     struct SwsContext* img_ctx = NULL;  
  14.   
  15.     SDL_Window* window = NULL;  
  16.     SDL_Renderer* renderer = NULL;  
  17.     SDL_Texture* texture = NULL;  
  18.     SDL_Rect rect= { 0 };  
  19.   
  20.     av_register_all();  
  21.     if(SDL_Init(SDL_INIT_VIDEO) != 0)  
  22.         return ERROR_INIT;  
  23.   
  24.     pFmtCtx = avformat_alloc_context();  
  25.     if ((iRes = avformat_open_input(&pFmtCtx, szFileName, NULL, NULL)) != 0)  
  26.         return ERROR_OPEN;  
  27.     if (avformat_find_stream_info(pFmtCtx, NULL) < 0)  
  28.         return ERROR_FIND;  
  29.     av_dump_format(pFmtCtx, -1, szFileName, NULL);  
  30.   
  31.     for (int i = 0; i < pFmtCtx->nb_streams; ++i)  
  32.     {  
  33.         if (pFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)  
  34.             vindex = i;  
  35.     }  
  36.     if (vindex == -1)  
  37.         return ERROR_FIND;  
  38.   
  39.     vCodecCtx = avcodec_alloc_context3(NULL);  
  40.     if(avcodec_parameters_to_context(vCodecCtx, pFmtCtx->streams[vindex]->codecpar) < 0)  
  41.         return ERROR_COPY;  
  42.     vCodec = avcodec_find_decoder(vCodecCtx->codec_id);  
  43.     if (!vCodec)  
  44.         return ERROR_FIND;  
  45.     if(avcodec_open2(vCodecCtx, vCodec, NULL) != 0)  
  46.         return ERROR_OPEN;  
  47.   
  48.     window = SDL_CreateWindow("video", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 680, 540, SDL_WINDOW_OPENGL);  
  49.     renderer = SDL_CreateRenderer(window, -1, 0);  
  50.     texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, vCodecCtx->width, vCodecCtx->height);  
  51.     if (!window || !renderer || !texture)  
  52.         return ERROR_CREATE;  
  53.     rect.w = vCodecCtx->width;  
  54.     rect.h = vCodecCtx->height;  
  55.   
  56.     img_ctx = sws_getContext(vCodecCtx->width, vCodecCtx->height, vCodecCtx->pix_fmt,  
  57.         vCodecCtx->width, vCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL,NULL);  
  58.     if (!img_ctx)  
  59.         return ERROR_GET;  
  60.     pkt = av_packet_alloc();  
  61.     pfe = av_frame_alloc();  
  62.     YUV = av_frame_alloc();  
  63.     buf = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, vCodecCtx->width, vCodecCtx->height,1));  
  64.     av_image_fill_arrays(YUV->data, YUV->linesize, buf, AV_PIX_FMT_YUV420P, vCodecCtx->width, vCodecCtx->height, 1);  
  65.     while (av_read_frame(pFmtCtx, pkt) >= 0)  
  66.     {  
  67.         if (pkt->stream_index == vindex)  
  68.         {  
  69.             if ((iRes = avcodec_send_packet(vCodecCtx, pkt)) != 0)  
  70.                 av_strerror(iRes, errbuf, 256);//return -5;  
  71.             if ((iRes=  avcodec_receive_frame(vCodecCtx, pfe)) != 0)  
  72.                 av_strerror(iRes, errbuf, 256); //return -6;  
  73.             sws_scale(img_ctx, pfe->data, pfe->linesize, 0, vCodecCtx->height, YUV->data, YUV->linesize);  
  74.               
  75.             SDL_UpdateTexture(texture, &rect, YUV->data[0], YUV->linesize[0]);  
  76.             SDL_RenderClear(renderer);  
  77.             SDL_RenderCopy(renderer, texture, NULL, NULL);  
  78.             SDL_RenderPresent(renderer);  
  79.         }  
  80.     }  
  81.       
  82.     av_free(buf);  
  83.     av_frame_free(&YUV);  
  84.     av_frame_free(&pfe);  
  85.     av_packet_free(&pkt);  
  86.     sws_freeContext(img_ctx);  
  87.     SDL_DestroyTexture(texture);  
  88.     SDL_DestroyRenderer(renderer);  
  89.     SDL_DestroyWindow(window);  
  90.     SDL_Quit();  
  91.     avcodec_free_context(&vCodecCtx);  
  92.     avformat_close_input(&pFmtCtx);  
  93.     avformat_free_context(pFmtCtx);  
  94.     return 0;  
  95. }  
  96.    

[cpp] view plain copy

  1. uint8_t* g_buf = NULL;  
  2. int g_MaxLen = 0;  
  3. int g_CurPos = 0;  
  4. void aCallback(void *userdata, Uint8 * stream, int len)  
  5. {  
  6.     SDL_memset(stream, 0, len);//important  
  7.     SDL_MixAudio(stream, g_buf, len, SDL_MIX_MAXVOLUME);//memcpy(stream, g_buf, len);  
  8.     g_CurPos += len;  
  9.     g_MaxLen -= len;  
  10. }  
  11.   
  12. int OpenAVFile(const char* szFileName)  
  13. {  
  14.     char errbuf[256] = { 0 };  
  15.     int iRes = 0;  
  16.     int aindex = -1;  
  17.     AVFormatContext* pFmtCtx = NULL;  
  18.     AVCodecContext* aCodecCtx = NULL;  
  19.     AVCodec* aCodec = NULL;  
  20.     AVPacket* pkt = NULL;  
  21.     AVFrame* pfe = NULL;  
  22.     uint8_t* buf = NULL;  
  23.     struct SwrContext* audio_ctx = NULL;  
  24.     SDL_AudioSpec want = { 0 };  
  25.     SDL_AudioSpec recv = { 0 };  
  26.   
  27.     av_register_all();  
  28.     if (SDL_Init(SDL_INIT_AUDIO) != 0)  
  29.         return ERROR_INIT;  
  30.   
  31.     pFmtCtx = avformat_alloc_context();  
  32.     if ((iRes = avformat_open_input(&pFmtCtx, szFileName, NULL, NULL)) != 0)  
  33.         return ERROR_OPEN;  
  34.     if (avformat_find_stream_info(pFmtCtx, NULL) < 0)  
  35.         return ERROR_FIND;  
  36.     av_dump_format(pFmtCtx, -1, szFileName, NULL);  
  37.   
  38.     for (int i = 0; i < pFmtCtx->nb_streams; ++i)  
  39.     {  
  40.         if (pFmtCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)  
  41.             aindex = i;  
  42.     }  
  43.     if (aindex == -1)  
  44.         return ERROR_FIND;  
  45.   
  46.     aCodecCtx = avcodec_alloc_context3(NULL);  
  47.     if (avcodec_parameters_to_context(aCodecCtx, pFmtCtx->streams[aindex]->codecpar) < 0)  
  48.         return ERROR_COPY;  
  49.     aCodec = avcodec_find_decoder(aCodecCtx->codec_id);  
  50.     if (!aCodec)  
  51.         return ERROR_FIND;  
  52.     if (avcodec_open2(aCodecCtx, aCodec, NULL) != 0)  
  53.         return ERROR_OPEN;  
  54.   
  55.     want.callback = aCallback;  
  56.     //want.channels = 1;//设为单声道就不用装换pannel了  
  57.     want.channels = aCodecCtx->channels;  
  58.     want.format = AUDIO_S16SYS;//ffmpeg的fmt与SDL的不一样,但是可以自己计算转换  
  59.     want.freq = aCodecCtx->sample_rate;  
  60.     want.samples = aCodecCtx->frame_size;  
  61.     want.silence = 0;  
  62.     want.userdata = aCodecCtx;  
  63.     SDL_OpenAudio(&want, &recv);  
  64.   
  65.     //audio_ctx = swr_alloc();  
  66.     audio_ctx = swr_alloc_set_opts(NULL, av_get_default_channel_layout(recv.channels), AV_SAMPLE_FMT_S16, recv.freq,  
  67.         av_get_default_channel_layout(aCodecCtx->channels), aCodecCtx->sample_fmt, aCodecCtx->sample_rate, 0, NULL);  
  68.     swr_init(audio_ctx);//必须要  
  69.   
  70.     pkt = av_packet_alloc();  
  71.     pfe = av_frame_alloc();  
  72.     g_buf = (uint8_t*)av_malloc(av_samples_get_buffer_size(NULL, recv.channels, recv.samples, AV_SAMPLE_FMT_S16, 1));  
  73.     while (av_read_frame(pFmtCtx, pkt) >= 0)  
  74.     {  
  75.         if (pkt->stream_index == aindex)  
  76.         {  
  77.             if ((iRes = avcodec_send_packet(aCodecCtx, pkt)) != 0)  
  78.                 av_strerror(iRes, errbuf, 256);//return -5;  
  79.             if ((iRes = avcodec_receive_frame(aCodecCtx, pfe)) != 0)  
  80.                 av_strerror(iRes, errbuf, 256); //return -6;  
  81.   
  82.             //单声道  
  83.             //memset(g_buf, 0, 10240);  
  84.             //memcpy(g_buf, pfe->data[0], pfe->linesize[0]);  
  85.             //g_CurPos = 0;  
  86.             //g_MaxLen = pfe->linesize[0];  
  87.   
  88.             swr_convert(audio_ctx, &g_buf, av_samples_get_buffer_size(NULL, recv.channels, recv.samples, AV_SAMPLE_FMT_S16, 1),   
  89.                 (const uint8_t **)pfe->data, pfe->nb_samples);  
  90.             g_CurPos = 0;  
  91.             g_MaxLen = av_samples_get_buffer_size(NULL, recv.channels, recv.samples, AV_SAMPLE_FMT_S16, 1);  
  92.   
  93.             SDL_PauseAudio(0);  
  94.             while (g_MaxLen > 0)  
  95.                 SDL_Delay(1);  
  96.         }  
  97.     }  
  98.   
  99.     av_free(buf);  
  100.     av_frame_free(&pfe);  
  101.     av_packet_free(&pkt);  
  102.     swr_free(&audio_ctx);  
  103.     SDL_Quit();  
  104.     avcodec_free_context(&aCodecCtx);  
  105.     avformat_close_input(&pFmtCtx);  
  106.     avformat_free_context(pFmtCtx);  
  107.     return 0;  
  108. }  

视频的重要处理:
sws_getContext,获得转换上下文

av_image_get_buffer_size,获得(转换后)图片大小

av_image_fill_arrays,将自定义内存块绑定到输出的AVFrame中

sws_scale,转换

音频的重要处理:

av_get_default_channel_layout,根据声道数获取默认的声道布局

swr_alloc_set_opts,获取转换上下文

swr_init,获取到上下文后必须初始化

av_samples_get_buffer_size,计算(参数格式的)音频数据的大小

swr_convert,转换


对于音频的相关参数,FFmpeg和SDL中的channels,sample_rate...等等这些"数值"都是可以直接互相赋值的。但是format,FFmpeg和SDL就各自有自己的定义。

下面是我自己做的由AVSampleFormat转SDL_AudioFormat的函数

[cpp] view plain copy

  1. /*{ 
  2. AV_SAMPLE_FMT_NONE = -1, 
  3. AV_SAMPLE_FMT_U8,          ///< unsigned 8 bits 
  4. AV_SAMPLE_FMT_S16,         ///< signed 16 bits 
  5. AV_SAMPLE_FMT_S32,         ///< signed 32 bits 
  6. AV_SAMPLE_FMT_FLT,         ///< float 
  7. AV_SAMPLE_FMT_DBL,         ///< double 
  8.  
  9. AV_SAMPLE_FMT_U8P,         ///< unsigned 8 bits, planar 
  10. AV_SAMPLE_FMT_S16P,        ///< signed 16 bits, planar 
  11. AV_SAMPLE_FMT_S32P,        ///< signed 32 bits, planar 
  12. AV_SAMPLE_FMT_FLTP,        ///< float, planar 
  13. AV_SAMPLE_FMT_DBLP,        ///< double, planar 
  14. AV_SAMPLE_FMT_S64,         ///< signed 64 bits 
  15. AV_SAMPLE_FMT_S64P,        ///< signed 64 bits, planar 
  16.  
  17. AV_SAMPLE_FMT_NB           ///< Number of sample formats. DO NOT USE if linking dynamically 
  18. }*/  
  19. /*  \verbatim 
  20. ++---------------------- - sample is signed if set 
  21. || 
  22. || ++---------- - sample is bigendian if set 
  23. || || 
  24. || || ++-- - sample is float if set 
  25. || || || 
  26. || || || +-- - sample bit size-- - + 
  27. || || || | | 
  28. 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 
  29. \endverbatim 
  30. *  There are macros in SDL 2.0 and later to query these bits. 
  31. */  
  32. SDL_AudioFormat GetFmt(AVSampleFormat avfmt)  
  33. {  
  34.     SDL_AudioFormat res = 0;  
  35.     bool isp = false;  
  36.     bool iss = false;  
  37.     bool isf = false;  
  38.     bool isd = false;  
  39.     int bits = 0;  
  40.     switch (avfmt)  
  41.     {  
  42.     case AV_SAMPLE_FMT_NONE://// = -1,  
  43.         break;  
  44.     case    AV_SAMPLE_FMT_U8:         ///< unsigned 8 bits  
  45.         bits = 8;  
  46.         break;  
  47.     case    AV_SAMPLE_FMT_S16:         ///< signed 16 bits  
  48.         bits = 16;  
  49.         iss = true;  
  50.         break;  
  51.     case AV_SAMPLE_FMT_S32:         ///< signed 32 bits  
  52.         bits = 32;  
  53.         iss = true;  
  54.         break;  
  55.     case AV_SAMPLE_FMT_FLT:         ///< float  
  56.         isf = true;  
  57.         break;  
  58.     case    AV_SAMPLE_FMT_DBL:         ///< double  
  59.         isd = true;  
  60.         break;  
  61.     case    AV_SAMPLE_FMT_U8P:         ///< unsigned 8 bits, planar  
  62.         bits = 8;  
  63.         isp = true;  
  64.         break;  
  65.     case    AV_SAMPLE_FMT_S16P:        ///< signed 16 bits, planar  
  66.         bits = 16;  
  67.         iss = true;  
  68.         isp = true;  
  69.         break;  
  70.     case    AV_SAMPLE_FMT_S32P:        ///< signed 32 bits, planar  
  71.         bits = 32;  
  72.         iss = true;  
  73.         isp = true;  
  74.         break;  
  75.     case    AV_SAMPLE_FMT_FLTP:        ///< float, planar  
  76.         isf = true;  
  77.         isp = true;  
  78.         break;  
  79.     case    AV_SAMPLE_FMT_DBLP:       ///< double, planar  
  80.         isd = true;  
  81.         isp = true;  
  82.         break;  
  83.     case    AV_SAMPLE_FMT_S64:        ///< signed 64 bits  
  84.         bits = 64;  
  85.         iss = true;  
  86.         break;  
  87.     case    AV_SAMPLE_FMT_S64P:       ///< signed 64 bits, planar  
  88.         bits = 64;  
  89.         iss = true;  
  90.         isp = true;  
  91.         break;  
  92.     case    AV_SAMPLE_FMT_NB:           ///< Number of sample formats. DO NOT USE if linking dynamically  
  93.         break;  
  94.     }  
  95.     if (iss)  
  96.         res |= 1 << 15;  
  97.     if (isf)  
  98.         res |= 1 << 8;  
  99.     bits &= 255;  
  100.     res |= bits;  
  101.   
  102.     return res;  
  103. }  

例子代码中为了简便,SDL播放音频的format就用AUDIO_S16SYS,对应FFmpeg就是AV_SAMPLE_FMT_S16,都标识signed 16bit。注意SDL中音频数据没有planner。

猜你喜欢

转载自blog.csdn.net/qq_21743659/article/details/107856801
今日推荐