您的位置:首页 > 其它

04 ffmpeg 从媒体文件解封装,输出YUV420图像

2017-10-30 01:16 441 查看
输出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]#
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息