04 ffmpeg 從媒體文件解封裝,輸出YUV420圖像
阿新 • • 發佈:2017-10-30
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圖像