ffmpeg解码YUV
方法1:命令解码
# 解码命令 ffmpeg -i input.mp4 -f rawvideo output.yuv # 播放命令 ffplay -s 720x1280 -pix_fmt yuv420p output.yuv
方法2:代码解码
main.c
#include "libavutil/log.h" #include "libavformat/avformat.h" #include "libavutil/avutil.h" #include "libavcodec/avcodec.h" int decodeVideo(AVCodecContext *codecCtx, AVPacket *packet, FILE *dst) { int ret = avcodec_send_packet(codecCtx, packet); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "avcodec_send_packet failed: %s\n", av_err2str(ret)); av_packet_unref(packet); return ret; } AVFrame *frame = av_frame_alloc(); while ((ret = avcodec_receive_frame(codecCtx, frame)) == 0) { // 写入YUV数据方法1 fwrite(frame->data[0], 1, codecCtx->width * codecCtx->height, dst); // Y data fwrite(frame->data[1], 1, codecCtx->width * codecCtx->height / 4, dst); // U data fwrite(frame->data[2], 1, codecCtx->width * codecCtx->height / 4, dst); // V data // 写入YUV数据方法2 // for (int i = 0; i < codecCtx->height; i++) { // fwrite(frame->data[0] + i * frame->linesize[0], 1, codecCtx->width, dst); // Y data // } // for (int i = 0; i < codecCtx->height / 2; i++) { // fwrite(frame->data[1] + i * frame->linesize[1], 1, codecCtx->width / 2, dst); // U data // } // for (int i = 0; i < codecCtx->height / 2; i++) { // fwrite(frame->data[2] + i * frame->linesize[2], 1, codecCtx->width / 2, dst); // V data // } } if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { av_frame_free(&frame); return 0; } else if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "avcodec_receive_frame failed: %s\n", av_err2str(ret)); av_frame_free(&frame); return ret; } av_frame_free(&frame); return 0; } int main(int argc, char **argv) { av_log_set_level(AV_LOG_DEBUG); if (argc < 3) { av_log(NULL, AV_LOG_ERROR, "Usage: %s inputFile outputFile\n", argv[0]); return -1; } const char *inputFile = argv[1]; const char *outputFile = argv[2]; AVFormatContext *fCtx = NULL; int ret; if ((ret = avformat_open_input(&fCtx, inputFile, NULL, NULL)) < 0) { av_log(NULL, AV_LOG_ERROR, "Open input file %s failed: %s\n", inputFile, av_err2str(ret)); return -1; } if ((ret = avformat_find_stream_info(fCtx, NULL)) < 0) { av_log(NULL, AV_LOG_ERROR, "Find input file stream info failed: %s\n", av_err2str(ret)); avformat_close_input(&fCtx); return -1; } ret = av_find_best_stream(fCtx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "av_find_best_stream failed: %s\n", av_err2str(ret)); avformat_close_input(&fCtx); return -1; } int videoIndex = ret; AVCodecContext *codecCtx = avcodec_alloc_context3(NULL); if (codecCtx == NULL) { av_log(NULL, AV_LOG_ERROR, "avcodec_alloc_context3 failed\n"); avformat_close_input(&fCtx); return -1; } if ((ret = avcodec_parameters_to_context(codecCtx, fCtx->streams[videoIndex]->codecpar)) < 0) { av_log(NULL, AV_LOG_ERROR, "avcodec_parameters_to_context failed: %s\n", av_err2str(ret)); avformat_close_input(&fCtx); avcodec_free_context(&codecCtx); return -1; } AVCodec *decoder = avcodec_find_decoder(codecCtx->codec_id); if (decoder == NULL) { av_log(NULL, AV_LOG_ERROR, "avcodec_find_decoder failed\n"); avformat_close_input(&fCtx); avcodec_free_context(&codecCtx); return -1; } if ((ret = avcodec_open2(codecCtx, decoder, NULL)) < 0) { av_log(NULL, AV_LOG_ERROR, "avcodec_open2 failed: %s\n", av_err2str(ret)); avformat_close_input(&fCtx); avcodec_free_context(&codecCtx); return -1; } FILE *dst = fopen(outputFile, "wb"); if (dst == NULL) { av_log(NULL, AV_LOG_ERROR, "open outputFile failed\n"); avformat_close_input(&fCtx); avcodec_free_context(&codecCtx); return -1; } AVPacket *packet = av_packet_alloc(); if (!packet) { av_log(NULL, AV_LOG_ERROR, "Could not allocate AVPacket\n"); avformat_close_input(&fCtx); avcodec_free_context(&codecCtx); fclose(dst); return -1; } while (av_read_frame(fCtx, packet) == 0) { if (packet->stream_index == videoIndex) { if (decodeVideo(codecCtx, packet, dst) < 0) { av_packet_unref(packet); break; } } av_packet_unref(packet); } decodeVideo(codecCtx, NULL, dst); // Cleanup av_packet_free(&packet); avformat_close_input(&fCtx); avcodec_free_context(&codecCtx); fclose(dst); return 0; }
Makefile
TARGET=main SRC=main.c CC=gcc CFLAGS=-I /usr/local/ffmpeg/include LDFLAGS=-L /usr/local/ffmpeg/lib LDFLAGS+= -lavutil -lavformat -lavcodec all:$(TARGET) $(TARGET):$(SRC) $(CC) $(SRC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) clean: rm -rf $(TARGET)