实现最小YUV视频解码器

本文记录了使用ffmpeg进行视频解码的最小解码器代码,通过这个小程序可以理解ffmpeg的解码过程及用到的api。这里将解码码后得到的YUV格式的视频保存到文件中,可以使用YUV Playe播放。代码已上传git,
https://github.com/beijixing/ffmpegStudy

流程图.jpg

extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/opt.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}

void devoder()
{
    //注册编解码器
    av_register_all();

    AVFormatContext *pAVFormatCtx = NULL;
    int ret = avformat_open_input(&pAVFormatCtx,"Titanic.mkv",NULL, NULL);
    if(ret != 0)
    {
        printf("avformat_open_input failed!");
        return;
    }

    //查找流信息
    ret = avformat_find_stream_info(pAVFormatCtx, NULL);
    if(ret != 0)
    {
        printf("avformat_find_stream_info failed!");
        return;
    }

    //查找视频流索引
   int videoIndex = -1;
   videoIndex = av_find_best_stream(pAVFormatCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, NULL);
   if(videoIndex < 0)
   {
       printf("av_find_best_stream failed!");
       return;
   }

   //查找解码器上下文
   AVCodecContext *pAVCodecCtx = pAVFormatCtx->streams[videoIndex]->codec;
   //查找解码器
   AVCodec *pAVCodec = avcodec_find_decoder(pAVCodecCtx->codec_id);

   if(pAVCodec == NULL)
   {
       printf("Codec not found.\n");
       return;
   }
    //打开解码器
   ret = avcodec_open2(pAVCodecCtx, pAVCodec, NULL);
   if(ret < 0)
   {
       printf("avcodec_open2 failed !\n");
       return;
   }

   //解码视频
   AVFrame *pAVFrame = av_frame_alloc();
   AVFrame *pAVFrameYUV = av_frame_alloc();

   //创建缓存
   int nBuffSize = av_image_get_buffer_size(AV_PIX_FMT_YUV420P, pAVCodecCtx->width, pAVCodecCtx->height, 1);
   unsigned char* buffer = (unsigned char *)av_malloc(nBuffSize);
   //设置缓存
   av_image_fill_arrays(pAVFrameYUV->data, pAVFrameYUV->linesize, buffer,
                        AV_PIX_FMT_YUV420P, pAVCodecCtx->width,
                        pAVCodecCtx->height, 1);
   //创建AVPacket
   AVPacket *pAVPacket = (AVPacket *)av_malloc(sizeof (AVPacket));
   //创建图像转换上下文
   SwsContext *pSwsCtx = sws_getContext(pAVCodecCtx->width, pAVCodecCtx->height,
                                       pAVCodecCtx->pix_fmt, pAVCodecCtx->width, pAVCodecCtx->height,
                                        AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);


   int gotPicture = 0;
   FILE* pYuvFile = fopen("test.yuv", "wb");
   if(!pYuvFile)
   {
       printf("fopen test.yuv failed !\n");
       return;
   }

   int frameCnt = 0;
   while (av_read_frame(pAVFormatCtx, pAVPacket) >= 0)
   {
       //只解码视频
       if(pAVPacket->stream_index == videoIndex)
       {
            ret = avcodec_decode_video2(pAVCodecCtx, pAVFrame, &gotPicture, pAVPacket);
            if(ret < 0)
            {
                printf("avcodec_decode_video2 failed !\n");
                break;
            }
            if(gotPicture)
            {
                //格式转换
                sws_scale(pSwsCtx, pAVFrame->data,
                          pAVFrame->linesize,
                          0,
                          pAVCodecCtx->height,
                          pAVFrameYUV->data,
                          pAVFrameYUV->linesize);
                fwrite(pAVFrameYUV->data[0],1,pAVCodecCtx->width*pAVCodecCtx->height, pYuvFile);
                fwrite(pAVFrameYUV->data[1],1,pAVCodecCtx->width*pAVCodecCtx->height/4, pYuvFile);
                fwrite(pAVFrameYUV->data[2],1,pAVCodecCtx->width*pAVCodecCtx->height/4, pYuvFile);
                frameCnt++;
                printf("frameCnt = %d !\n", frameCnt);
            }

       }
   }

   //释放指针
   fclose(pYuvFile);
   sws_freeContext(pSwsCtx);
   av_frame_free(&pAVFrame);
   av_frame_free(&pAVFrameYUV);
   av_packet_free(&pAVPacket);
   avformat_close_input(&pAVFormatCtx);
}


int main(int argc, char *argv[])
{
    devoder();
    return 0;
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,053评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,527评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,779评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,685评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,699评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,609评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,989评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,654评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,890评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,634评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,716评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,394评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,976评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,950评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,191评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,849评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,458评论 2 342

推荐阅读更多精彩内容