将 h264 格式转换为YUV数据

废话少说,直接贴上代码。

decode_yuv.c

/*
 * =====================================================================================
 *
 *       Filename:  decode_yuv.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  11/15/17 15:26:12
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  linsheng.pan (), life_is_legend@163.com
 *   Organization:  
 *
 * =====================================================================================
 */
#include <stdlib.h>


#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavutil/imgutils.h>


void usage(void)
{
    printf("decode_yuv input_file output_file.yuv\n");
}


int main(int argc, char *argv[])
{

    if(argc != 3)
    {
        usage();
        return -1;
    }


    char *input_file = argv[1];
    char *output_file = argv[2];


    AVFormatContext *pFormatCtx = NULL;
    AVCodecContext *pCodecCtx = NULL;
    AVCodec *pCodec = NULL;
    AVFrame *pFrameYUV = NULL;
    AVFrame *pFrame = NULL;
    AVPacket *packet = NULL;
    uint32_t i = 0;
    int videoindex = -1;
    int y_size = -1;
    int ret = 0;
    int got_picture = 0;
    uint8_t *out_buffer = NULL;
    struct SwsContext *img_convert_ctx = NULL;


    FILE *fp = fopen(output_file, "wb+");


    av_register_all();
    avformat_network_init();


    pFormatCtx = avformat_alloc_context();
    if(!pFormatCtx)
    {
        printf("Error: call avformat_alloc_context failed!");
        return -1;
    }


    //打开视频文件
    if(0 != avformat_open_input(&pFormatCtx, input_file, NULL, NULL))
    {
        printf("Error: call avformat_open_input failed!\n");
        return -1;
    }


    //获取视频信息
    if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
    {
        printf("Error: call avformat_find_stream_info failed!\n");
        return -1;
    }


    //查找解码器
    videoindex = -1;
    for(i = 0; i < pFormatCtx->nb_streams; ++i)
    {
        if(AVMEDIA_TYPE_VIDEO == pFormatCtx->streams[i]->codec->codec_type)
        {
            videoindex = i;
            break;
        }
    }
    if(-1 == videoindex)
    {
        printf("Error: can't find a video stream!\n");
        return -1;
    }
    pCodecCtx = pFormatCtx->streams[videoindex]->codec;
    pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
    if(!pCodec)
    {
        printf("Error: Codec not find!\n");
        return -1;
    }


    //打开解码器
    if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
    {
        printf("Error: Can't open codec!\n");
        return -1;
    }

    printf("width = %d\n", pCodecCtx->width);
    printf("height = %d\n", pCodecCtx->height);


    //将pFrameYUV 和 out_buffer 关联上
    pFrame = av_frame_alloc();
    pFrameYUV = av_frame_alloc();
    out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));
    avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);


    packet = (AVPacket *)av_malloc(sizeof(AVPacket));
    av_init_packet(packet);
    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);


    //打印文件信息
    printf("#------------------------------#\n");
    av_dump_format(pFormatCtx, 0, input_file, 0);
    printf("#------------------------------#\n");

    while(av_read_frame(pFormatCtx, packet) >= 0)
    {
        if(videoindex == packet->stream_index)
        {
           ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
           if(ret < 0)
           {
               printf("Error: Decode failed!\n");
               return -1;
           }


           if(got_picture)
           {
               sws_scale(img_convert_ctx, (uint8_t *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);


               y_size = pCodecCtx->width * pCodecCtx->height;
               fwrite(pFrameYUV->data[0], 1, y_size, fp);
               fwrite(pFrameYUV->data[1], 1, y_size/4, fp);
               fwrite(pFrameYUV->data[2], 1, y_size/4, fp);
               printf("Succeed to decode 1 Frame!\n");
           }
        }

        av_free_packet(packet);
    }


    //flush decoder
    //当av_read_frame 退出循环的时候,实际上解码器中可能还包含
    //剩余的几帧数据。直接调用avcodec_decode_video2获得AVFrame ,
    //而不再向解码器传递AVPacket
    while(1)
    {
        ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);
        if(ret < 0)
        {
            break;
        }
        if(!got_picture)
        {
            break;
        }


        sws_scale(img_convert_ctx, (uint8_t *)pFrame->data, pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data, pFrameYUV->linesize);


        y_size = pCodecCtx->width * pCodecCtx->height;
        fwrite(pFrameYUV->data[0], 1, y_size, fp);
        fwrite(pFrameYUV->data[1], 1, y_size/4, fp);
        fwrite(pFrameYUV->data[2], 1, y_size/4, fp);
        printf("Succeed to decode 1 Frame!\n");


    }


    sws_freeContext(img_convert_ctx);
    fclose(fp);
    av_frame_free(&pFrame);
    av_frame_free(&pFrameYUV);
    avcodec_close(pCodecCtx);
    avformat_close_input(&pFormatCtx);


    return 0;
}

编译gcc decode_yuv.c -o decode_yuv -lavformat -lavcodec -lavutil -lswscale

posted @ 2020-03-23 16:49  standardzero  阅读(2566)  评论(0编辑  收藏  举报