您当前的位置: 首页 >  音视频

鱼儿-1226

暂无认证

  • 0浏览

    0关注

    1100博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

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

鱼儿-1226 发布时间:2020-08-07 10:29:34 ,浏览量:0

  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) streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)  
  28.             vindex = i;  
  29.     }  
  30.     if (vindex == -1)  
  31.         return ERROR_FIND;  
  32.   
  33.     vCodecCtx = avcodec_alloc_context3(NULL);  
  34.     if(avcodec_parameters_to_context(vCodecCtx, pFmtCtx->streams[vindex]->codecpar) codec_id);  
  35.     if (!vCodec)  
  36.         return ERROR_FIND;  
  37.     if(avcodec_open2(vCodecCtx, vCodec, NULL) != 0)  
  38.         return ERROR_OPEN;  
  39.   
  40.     window = SDL_CreateWindow("video", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 680, 540, SDL_WINDOW_OPENGL);  
  41.     renderer = SDL_CreateRenderer(window, -1, 0);  
  42.     texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_IYUV, SDL_TEXTUREACCESS_STREAMING, vCodecCtx->width, vCodecCtx->height);  
  43.     if (!window || !renderer || !texture)  
  44.         return ERROR_CREATE;  
  45.     rect.w = vCodecCtx->width;  
  46.     rect.h = vCodecCtx->height;  
  47.   
  48.     img_ctx = sws_getContext(vCodecCtx->width, vCodecCtx->height, vCodecCtx->pix_fmt,  
  49.         vCodecCtx->width, vCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL,NULL);  
  50.     if (!img_ctx)  
  51.         return ERROR_GET;  
  52.     pkt = av_packet_alloc();  
  53.     pfe = av_frame_alloc();  
  54.     YUV = av_frame_alloc();  
  55.     buf = (uint8_t*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_YUV420P, vCodecCtx->width, vCodecCtx->height,1));  
  56.     av_image_fill_arrays(YUV->data, YUV->linesize, buf, AV_PIX_FMT_YUV420P, vCodecCtx->width, vCodecCtx->height, 1);  
  57.     while (av_read_frame(pFmtCtx, pkt) >= 0)  
  58.     {  
  59.         if (pkt->stream_index == vindex)  
  60.         {  
  61.             if ((iRes = avcodec_send_packet(vCodecCtx, pkt)) != 0)  
  62.                 av_strerror(iRes, errbuf, 256);//return -5;  
  63.             if ((iRes=  avcodec_receive_frame(vCodecCtx, pfe)) != 0)  
  64.                 av_strerror(iRes, errbuf, 256); //return -6;  
  65.             sws_scale(img_ctx, pfe->data, pfe->linesize, 0, vCodecCtx->height, YUV->data, YUV->linesize);  
  66.               
  67.             SDL_UpdateTexture(texture, &rect, YUV->data[0], YUV->linesize[0]);  
  68.             SDL_RenderClear(renderer);  
  69.             SDL_RenderCopy(renderer, texture, NULL, NULL);  
  70.             SDL_RenderPresent(renderer);  
  71.         }  
  72.     }  
  73.       
  74.     av_free(buf);  
  75.     av_frame_free(&YUV);  
  76.     av_frame_free(&pfe);  
  77.     av_packet_free(&pkt);  
  78.     sws_freeContext(img_ctx);  
  79.     SDL_DestroyTexture(texture);  
  80.     SDL_DestroyRenderer(renderer);  
  81.     SDL_DestroyWindow(window);  
  82.     SDL_Quit();  
  83.     avcodec_free_context(&vCodecCtx);  
  84.     avformat_close_input(&pFmtCtx);  
  85.     avformat_free_context(pFmtCtx);  
  86.     return 0;  
  87. }  
  88.    

[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) streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)  
  35.             aindex = i;  
  36.     }  
  37.     if (aindex == -1)  
  38.         return ERROR_FIND;  
  39.   
  40.     aCodecCtx = avcodec_alloc_context3(NULL);  
  41.     if (avcodec_parameters_to_context(aCodecCtx, pFmtCtx->streams[aindex]->codecpar) codec_id);  
  42.     if (!aCodec)  
  43.         return ERROR_FIND;  
  44.     if (avcodec_open2(aCodecCtx, aCodec, NULL) != 0)  
  45.         return ERROR_OPEN;  
  46.   
  47.     want.callback = aCallback;  
  48.     //want.channels = 1;//设为单声道就不用装换pannel了  
  49.     want.channels = aCodecCtx->channels;  
  50.     want.format = AUDIO_S16SYS;//ffmpeg的fmt与SDL的不一样,但是可以自己计算转换  
  51.     want.freq = aCodecCtx->sample_rate;  
  52.     want.samples = aCodecCtx->frame_size;  
  53.     want.silence = 0;  
  54.     want.userdata = aCodecCtx;  
  55.     SDL_OpenAudio(&want, &recv);  
  56.   
  57.     //audio_ctx = swr_alloc();  
  58.     audio_ctx = swr_alloc_set_opts(NULL, av_get_default_channel_layout(recv.channels), AV_SAMPLE_FMT_S16, recv.freq,  
  59.         av_get_default_channel_layout(aCodecCtx->channels), aCodecCtx->sample_fmt, aCodecCtx->sample_rate, 0, NULL);  
  60.     swr_init(audio_ctx);//必须要  
  61.   
  62.     pkt = av_packet_alloc();  
  63.     pfe = av_frame_alloc();  
  64.     g_buf = (uint8_t*)av_malloc(av_samples_get_buffer_size(NULL, recv.channels, recv.samples, AV_SAMPLE_FMT_S16, 1));  
  65.     while (av_read_frame(pFmtCtx, pkt) >= 0)  
  66.     {  
  67.         if (pkt->stream_index == aindex)  
  68.         {  
  69.             if ((iRes = avcodec_send_packet(aCodecCtx, pkt)) != 0)  
  70.                 av_strerror(iRes, errbuf, 256);//return -5;  
  71.             if ((iRes = avcodec_receive_frame(aCodecCtx, pfe)) != 0)  
  72.                 av_strerror(iRes, errbuf, 256); //return -6;  
  73.   
  74.             //单声道  
  75.             //memset(g_buf, 0, 10240);  
  76.             //memcpy(g_buf, pfe->data[0], pfe->linesize[0]);  
  77.             //g_CurPos = 0;  
  78.             //g_MaxLen = pfe->linesize[0];  
  79.   
  80.             swr_convert(audio_ctx, &g_buf, av_samples_get_buffer_size(NULL, recv.channels, recv.samples, AV_SAMPLE_FMT_S16, 1),   
  81.                 (const uint8_t **)pfe->data, pfe->nb_samples);  
  82.             g_CurPos = 0;  
  83.             g_MaxLen = av_samples_get_buffer_size(NULL, recv.channels, recv.samples, AV_SAMPLE_FMT_S16, 1);  
  84.   
  85.             SDL_PauseAudio(0);  
  86.             while (g_MaxLen > 0)  
  87.                 SDL_Delay(1);  
  88.         }  
  89.     }  
  90.   
  91.     av_free(buf);  
  92.     av_frame_free(&pfe);  
  93.     av_packet_free(&pkt);  
  94.     swr_free(&audio_ctx);  
  95.     SDL_Quit();  
  96.     avcodec_free_context(&aCodecCtx);  
  97.     avformat_close_input(&pFmtCtx);  
  98.     avformat_free_context(pFmtCtx);  
  99.     return 0;  
  100. }  

 

 

视频的重要处理: 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,          ///
关注
打赏
1604459285
查看更多评论
立即登录/注册

微信扫码登录

0.0402s