解码视频文件,保存音频文件为PCM,保存视频文件为yuv
1. 注册所有容器格式和CODEC:av_register_all()
2. 打开文件:avformat_open_input()
3. 从文件中提取流信息:avformat_find_stream_info()
4. 查找视频流音频流索引:av_find_best_stream()
5. 查找对应的解码器:avcodec_find_decoder()
6. 打开编解码器:avcodec_open2()
7. 为解码帧分配内存:av_frame_alloc()
8. 不停地从码流中提取出帧数据:av_read_frame()
9. 进行解码:avcodec_send_packet()
10. 获取解码后的数据:avcodec_receive_frame()
11. 解码完后,释放解码器:avcodec_close()
12. 关闭输入文件:avformat_close_input()
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
};
//输入文件路径
char *fileName = "";
int main()
{
//output file
FILE *outputfile_video = nullptr;
FILE *outputfile_audio = nullptr;
char *outputfilename_video = "output_video.yuv";
char *outputfilename_audio = "output_audio.pcm";
outputfile_video = fopen(outputfilename_video, "wb");
outputfile_audio = fopen(outputfilename_audio, "wb");
AVFormatContext *formatctx = NULL;
AVCodec *videoCodec = NULL;
AVCodec *audioCodec = NULL;
AVCodecContext *videoCodecctx = NULL;
AVCodecContext *audioCodecctx = NULL;
AVFrame *frame = NULL;
AVFrame *frameYUV = NULL;
AVPacket avpkt;
AVPacket *pavpkt = &avpkt;
//init
av_register_all();
formatctx = avformat_alloc_context();
//打开文件
if (avformat_open_input(&formatctx,fileName,NULL,NULL)!=0)
{
printf("could not open input stream.\n");
return -1;
}
//查找流信息
if (avformat_find_stream_info(formatctx, NULL) < 0)
{
printf("could not find stream information.\n");
return -1;
}
//==============video================
//查找视频流
int videoindex = av_find_best_stream(formatctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (videoindex < 0)
{
printf("could not find a video stream.\n");
return -1;
}
//find the video decoder
videoCodecctx = avcodec_alloc_context3(NULL);
if (videoCodecctx == NULL)
{
printf("could not allocate video AVCodecContext.\n");
return -1;
}
avcodec_parameters_to_context(videoCodecctx, formatctx->streams[videoindex]->codecpar);
videoCodec = avcodec_find_decoder(videoCodecctx->codec_id);
if (videoCodec == NULL)
{
printf("vidoe codec not found.\n");
return -1;
}
//open the video decoder
if (avcodec_open2(videoCodecctx, videoCodec, NULL) < 0)
{
printf("could not open video codec.\n");
return -1;
}
//=====================================
//================audio===================
//查找音频
int audioindex = av_find_best_stream(formatctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
if (audioindex < 0)
{
printf("could not find a audio stream.\n");
return -1;
}
//find the audio decoder
audioCodecctx = avcodec_alloc_context3(NULL);
if (audioCodecctx == NULL)
{
printf("could not allocate audio AVCodecContext.\n");
return -1;
}
avcodec_parameters_to_context(audioCodecctx, formatctx->streams[audioindex]->codecpar);
audioCodec = avcodec_find_decoder(audioCodecctx->codec_id);
if (audioCodec == NULL)
{
printf("audio codec not found.\n");
return -1;
}
//open the audio decoder
if (avcodec_open2(audioCodecctx, audioCodec, NULL) < 0)
{
printf("could not open audio codec.\n");
return -1;
}
//========================================
//output information
av_dump_format(formatctx, videoindex, fileName, 0);
av_init_packet(&avpkt);
frame = av_frame_alloc();
frameYUV = av_frame_alloc();
int video_dst_bufsize = av_image_alloc((uint8_t**)frameYUV->data, frameYUV->linesize, videoCodecctx->width, videoCodecctx->height, videoCodecctx->pix_fmt, 1);
printf("decode video file %s to %s and %s\n", fileName, outputfilename_video, outputfilename_audio);
//decode
int frame_count = 0;
while (av_read_frame(formatctx,pavpkt)>=0)
{
if (pavpkt->stream_index == videoindex)
{
if (avcodec_send_packet(videoCodecctx, pavpkt) != 0)
{
printf("input AVPacket to video decoder failed!\n");
return -1;
}
while (0 == avcodec_receive_frame(videoCodecctx, frame))
{
av_image_copy((uint8_t **)frameYUV->data,frameYUV->linesize,(const uint8_t **)frame->data,frame->linesize,videoCodecctx->pix_fmt,videoCodecctx->width,videoCodecctx->height);
fwrite(frameYUV->data[0], 1, video_dst_bufsize, outputfile_video);
printf("decoded frame index: %d\n", frame_count);
frame_count++;
}
}
else if (pavpkt->stream_index == audioindex)
{
if (avcodec_send_packet(audioCodecctx, pavpkt) != 0)
{
printf("input AVPacket to audio decoder failed!\n");
return -1;
}
while (0 == avcodec_receive_frame(audioCodecctx, frame))
{
size_t unpadded_linesize = frame->nb_samples*av_get_bytes_per_sample((AVSampleFormat)frame->format);
fwrite(frame->extended_data[0], 1, unpadded_linesize, outputfile_audio);
printf("decoded audio.\n");
}
}
av_packet_unref(pavpkt);
}
fclose(outputfile_video);
fclose(outputfile_audio);
av_frame_free(&frame);
av_frame_free(&frameYUV);
avcodec_close(videoCodecctx);
avcodec_close(audioCodecctx);
avformat_close_input(&formatctx);
return 0;
}
下一篇将介绍一下 PCM文件编码为AAC