1. 程式人生 > >04 ffmpeg 從媒體文件解封裝,輸出YUV420圖像

04 ffmpeg 從媒體文件解封裝,輸出YUV420圖像

ffmpeg 從媒體文件解封裝 輸出yuv420圖像



輸出AAC聲音目前有點問題:

輸出YUV420 很好

[root@localhost 04]# cat main.c 
#include <stdio.h>

#include "libavformat/avformat.h"

int frame_width = 0;
int frame_height = 0;
const char *src_filename = NULL;
const char *video_filename = NULL;
const char *audio_filename = NULL;
unsigned char *video_dst_data[4];
int video_dst_linesize[4];
int video_dst_buffersize;

enum AVPixelFormat pix_fmt;

//tmp var
AVFormatContext *fmt_ctx = NULL;
AVStream *pStream = NULL;
AVCodec *pcodec = NULL;
AVCodecContext *pCodecContext = NULL;

//video & audio var
AVStream *pVideoStream = NULL;
AVStream *pAudioStream = NULL;
AVCodecContext *pVideoCodecContext = NULL;
AVCodecContext *pAudioCodecContext = NULL;

FILE *pFilein = NULL;
FILE *pFileVideoOut = NULL;
FILE *pFileAudioOut = NULL;

AVFrame *frame = NULL;
AVPacket packet;


static int open_codec_context(enum AVMediaType type)
{
    int ret = 0;
    ret = av_find_best_stream(fmt_ctx, type, -1, -1, NULL, 0);
    if(ret < 0)
    {
        printf("av_find_best_stream fail [%d]\n", ret);
        return -1;
    }
    printf("av_find_best_stream OK [%d] \n", ret);
    pStream = fmt_ctx->streams[ret];
    pCodecContext = pStream->codec;

    pcodec = avcodec_find_decoder(pCodecContext->codec_id);
    if(NULL == pcodec)
    {
        printf("avcodec_find_decoder error \n");
        return -1;
    }

    ret = avcodec_open2(pCodecContext, pcodec, NULL);
    if(ret < 0)
    {
        printf("avcodec_open2 error [%d]", ret);
        return -1;

    }

}


static int decode_packet(int *got_frame)
{
    int ret = 0 ;

    if(packet.stream_index == pVideoStream->index)
    {
        //該packet屬於視頻
        ret = avcodec_decode_video2(pVideoCodecContext, frame, got_frame, &packet);
        printf("deal audio packet size=[%d], ", packet.size);
        if(ret < 0)
        {
            printf("Error: decodec video frame \n");
            return -1;
        }
        if(*got_frame)
        {
            printf("got audio frame, packet size=[%d]\n", packet.size);
            av_image_copy(video_dst_data, video_dst_linesize,
                    (const char **)frame->data, frame->linesize,
                    pix_fmt,
                    frame_width, frame_height);

            fwrite(video_dst_data[0],1, video_dst_buffersize, pFileVideoOut);
        }

    }
    else if(packet.stream_index == pAudioStream->index)
    {
        //該packet屬於音頻
        ret = avcodec_decode_audio4(pAudioCodecContext, frame, got_frame, &packet);
        printf("deal audio packet size=[%d], ", packet.size);
        if(ret < 0)
        {
            printf("Error: decodec audio frame \n");
            return -1;
        }
        if(*got_frame)
        {
            printf("got video frame, packet size=[%d]\n", packet.size);
            size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample(frame->format);
            fwrite(frame->extended_data[0], 1, unpadded_linesize, pFileAudioOut);
        }
    }
    else
    {

        printf("unknow stream \n");
        exit(0);
    }

    return  packet.size;
}

int main(int argc, char **argv)
{
    int ret = 0;

    if(argc == 4)
    {
        src_filename = argv[1];
        video_filename = argv[2];
        audio_filename = argv[3];
        printf("parameter OK \n");
        printf("src_filename:[%s] \n", src_filename);
        printf("video_filename:[%s] \n", video_filename);
        printf("audio_filename:[%s] \n", audio_filename);
    }
    else
    {
        printf("parameter ERROR: \n");
        return -1;
    }

    //加載編解碼器
    av_register_all();

    //根據輸入的視頻文件初始化 AVFormatContext
    ret = avformat_open_input(&fmt_ctx, src_filename, NULL, NULL);
    if(ret < 0)
    {
        printf("ERROR avformat_open_input fail [%d] \n", ret);
        return -1;
    }
    printf("avformat_open_input OK [%d] \n", ret);

    //根據視頻信息,查找解碼器
    ret = avformat_find_stream_info(fmt_ctx, NULL);
    if(ret < 0)
    {
        printf("ERROR avformat_find_stream_info [%d]\n", ret);
        return -1;
    }
    printf("avformat_find_stream_info OK [%d] \n", ret);


    //打開視頻
    ret = open_codec_context(AVMEDIA_TYPE_VIDEO);
    if(ret < 0)
    {
        printf("open_codec_context ERROR [%d]", ret);
        return -1;
    }
    pVideoStream = pStream;
    pVideoCodecContext = pCodecContext;
    frame_width = pVideoCodecContext->width;
    frame_height = pVideoCodecContext->height;
    pix_fmt = pVideoCodecContext->pix_fmt;
    printf("frame_width=[%d] \n", frame_width);
    printf("frame_height=[%d] \n", frame_height);

    ret = av_image_alloc(video_dst_data, video_dst_linesize, frame_width, frame_height, pix_fmt, 1);
    if(ret < 0)
    {
        printf("av_image_alloc error [%d] \n", ret);
        return -1;
    }
    printf("av_image_alloc buffersize=[%d] \n", ret);
    video_dst_buffersize = ret;


    pFileVideoOut = fopen(video_filename, "wb");
    if(NULL == pFileVideoOut)
    {
        printf("foopen video_filename ERROR\n");
        return -1;
    }



    // 打開音頻
    ret = open_codec_context(AVMEDIA_TYPE_AUDIO);
    if(ret < 0)
    {
        printf("open_codec_context Audio ERROR [%d]", ret);
        return -1;
    }
    pAudioStream = pStream;
    pAudioCodecContext = pCodecContext;

    pFileAudioOut = fopen(audio_filename, "wb");
    if(NULL == pFileAudioOut)
    {
        printf("foopen audio_filename ERROR\n");
        return -1;
    }


    av_dump_format(fmt_ctx, 0, src_filename, 0);//輸出信息


    //讀取和處理音視頻數據
    frame = av_frame_alloc();
    if(NULL == frame)
    {
        printf("av_frame_alloc error \n");
        return -1;
    }
    printf("av_frame_alloc OK \n");

    av_init_packet(&packet);
    packet.data = NULL;
    packet.size = 0 ;


    int get_frame_flags;
    while(av_read_frame(fmt_ctx, &packet) >= 0)//從文件中讀取出1幀
    {
        while(packet.size > 0)
        {
            ret = decode_packet(&get_frame_flags);
            packet.data += ret;
            packet.size -= ret;
        }

    }
    //處理緩存區的數據
    packet.data = NULL;
    packet.size = 0;
    while(get_frame_flags)
    {
        ret = decode_packet(&get_frame_flags);
        packet.data += ret;
        packet.size -= ret;
    }

    //收尾工作
    avcodec_close(pVideoCodecContext);
    avcodec_close(pAudioCodecContext);
    avformat_close_input(&fmt_ctx);
    av_frame_free(&frame);
    av_free(video_dst_data[0]);
    fclose(pFilein);
    fclose(pFileVideoOut);
    fclose(pFileAudioOut);


    return 0;
}
[root@localhost 04]#






Makefile 與使用方法:

[root@localhost 04]# cat makefile 
FLAGS = -g
INCLUDEPATH = -I /home/ffmpeg_dev/include/
LIBPATH = -L  /home/ffmpeg_dev/lib/
LIBS= -l avcodec          -l pthread          -l avutil           -l m                -l dl               -l swresample       -l avformat   
exe=test

$(exe):
	gcc main.c  ${FLAGS}  ${INCLUDEPATH} ${LIBPATH} ${LIBS} -o $@

clean:
	rm -rf ${exe}

[root@localhost 04]# 
[root@localhost 04]# cat auto.sh 
clear
make clean
make
./test in.mp4  out.yuv out.aac
[root@localhost 04]#






本文出自 “李春利” 博客,轉載請與作者聯系!

04 ffmpeg 從媒體文件解封裝,輸出YUV420圖像