温习ffmpeg的使用
1. 主要函数的调用流程
av_register_all 注册编解码器
avformat_alloc_context 初始化封装格式上下文, 用于mp4等视频格式的封装和解封装
avformat_open_input 解封装一个视频文件
avcodec_find_decoder 查找视频流解码器
av_read_frame 读取视频流的h264帧数据
avcodec_send_packet 将h264帧数据发送给解码器
avcodec_receive_frame 从解码器中读出解码后的yuv数据
2. 主要步骤
解封装视频文件 需要用到avformat开头的函数
在视频文件中找到视频流的解码器并且打开解码器
循环从视频文件中读取h264帧数据交给解码器解码,并且从解码器中读取解码后的yuv数据,最后写入yuv.data文件中
各种关闭
3.详细代码
void decode() {
char *path = "d:/mvresult.mp4";
av_register_all();//注册编解码器
AVFormatContext *avformat_context = avformat_alloc_context(); //初始化封装格式上下文
avformat_open_input(&avformat_context, path, NULL, NULL); //打开视频文件
int videoStream = -1;
for(int i = 0; i < avformat_context->nb_streams; i++) {//查找视频流
if (avformat_context->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
}
}
if (videoStream == -1) {
return;
}
AVCodecContext *avcodec_context = avformat_context->streams[videoStream]->codec;
AVCodec *codec = avcodec_find_decoder(avcodec_context->codec_id);//查找视频流的解码器
if (avcodec_open2(avcodec_context, codec, nullptr) < 0) {//打开解码器
return;
}
AVFrame *frame = av_frame_alloc();
AVPacket *packet = av_packet_alloc();
av_init_packet(packet);
FILE* pFile = fopen("d:/yuv420.data", "w");
SwsContext* sws_context = sws_getContext(avcodec_context->width, avcodec_context->height,
avcodec_context->pix_fmt, avcodec_context->width, avcodec_context->height,
AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
AVFrame *pFrameYUV = av_frame_alloc();
unsigned char * out_buffer = (uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, avcodec_context->width, avcodec_context->height));
avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, avcodec_context->width, avcodec_context->height);
int index = 0;
while(true) {
av_read_frame(avformat_context, packet);//读取文件中的h264帧
if (packet->stream_index == videoStream) {
int ret = avcodec_send_packet(avcodec_context, packet);//将h264帧发送到解码器
if (ret < 0) {
break;
}
while (true) {
int ret = avcodec_receive_frame(avcodec_context, frame);//从解码器获取帧
if (ret) {
break;
}
sws_scale(sws_context,(uint8_t const * const *) frame->data,
frame->linesize, 0, avcodec_context->height, pFrameYUV->data,
pFrameYUV->linesize);//将帧数据转为yuv420p
fwrite(pFrameYUV->data[0], sizeof( uint8_t ), avcodec_context->width * avcodec_context->height, pFile);//将y数据写入文件中
fwrite(pFrameYUV->data[1], sizeof( uint8_t ), avcodec_context->width * avcodec_context->height / 4, pFile);//将u数据写入文件中
fwrite(pFrameYUV->data[2], sizeof( uint8_t ), avcodec_context->width * avcodec_context->height / 4, pFile);//将v数据写入文件中
}
}
}
sws_freeContext(sws_context);
av_frame_free(&frame);
av_packet_free(&packet);
avcodec_close(avcodec_context);
avformat_close_input(&avformat_context);
fclose(pFile);
}