ffmpeg编码之实现YUV转换成H264
方法1:命令转换
# 转换 ffmpeg -s 720*1280 -pix_fmt yuv420p -i input.yuv -vcodec libx264 -b:v 4096k -bf 0 -g 10 -r 30 output.h264 # 播放 ffplay output.h264
方法2:代码转换
main.c
#include "libavutil/log.h" #include "libavutil/avutil.h" #include "libavcodec/avcodec.h" #include "libavutil/parseutils.h" #include "libavutil/imgutils.h" int writeFrameCount = 0; int encodeVideo(AVCodecContext *encodeCtx, AVFrame *frame, AVPacket *packet, FILE *dest) { int ret = avcodec_send_frame(encodeCtx, frame); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "avcodec_send_frame failed: %s\n", av_err2str(ret)); return ret; } else{ ret = avcodec_receive_packet(encodeCtx, packet); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { return 0; } else if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "avcodec_receive_packet failed: %s\n", av_err2str(ret)); return ret; } fwrite(packet->data, 1, packet->size, dest); av_log(NULL,AV_LOG_INFO,"write frame index = %d\n",writeFrameCount); writeFrameCount ++; av_packet_unref(packet); } return 0; } int main(int argc, char **argv) { av_log_set_level(AV_LOG_DEBUG); if (argc < 5) { av_log(NULL, AV_LOG_ERROR, "Usage: %s inputFile outputFile encoderName <width*height>\n", argv[0]); return -1; } const char *inputFile = argv[1]; const char *outputFile = argv[2]; const char *encodeName = argv[3]; const char *dstVideoSizeString = argv[4]; int ret; int dstHeight = 0; int dstWidth = 0; ret = av_parse_video_size(&dstWidth, &dstHeight, dstVideoSizeString); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "av_parse_video_size failed: %s\n", av_err2str(ret)); return -1; } AVCodec *encoder = avcodec_find_encoder_by_name(encodeName); if (encoder == NULL) { av_log(NULL, AV_LOG_ERROR, "avcodec_find_encoder_by_name failed\n"); return -1; } AVCodecContext *encodeCtx = avcodec_alloc_context3(encoder); if (encodeCtx == NULL) { av_log(NULL, AV_LOG_ERROR, "avcodec_alloc_context3 failed\n"); return -1; } enum AVPixelFormat pix_fmt = AV_PIX_FMT_YUV420P; encodeCtx->codec_type = AVMEDIA_TYPE_VIDEO; encodeCtx->pix_fmt = pix_fmt; encodeCtx->width = dstWidth; encodeCtx->height = dstHeight; encodeCtx->time_base = (AVRational) {1, 30}; encodeCtx->max_b_frames = 0; encodeCtx->gop_size = 10; ret = avcodec_open2(encodeCtx, encoder, NULL); if (ret < 0) { av_log(NULL, AV_LOG_ERROR, "avcodec_open2 failed: %s\n", av_err2str(ret)); avcodec_free_context(&encodeCtx); return -1; } FILE *inFp = fopen(inputFile, "rb"); if (inFp == NULL) { av_log(NULL, AV_LOG_ERROR, "open inputFile failed\n"); avcodec_free_context(&encodeCtx); return -1; } FILE *destFp = fopen(outputFile, "wb"); if (destFp == NULL) { av_log(NULL, AV_LOG_ERROR, "open outputFile failed\n"); avcodec_free_context(&encodeCtx); fclose(inFp); return -1; } AVFrame *frame = av_frame_alloc(); int frameSize = av_image_get_buffer_size(pix_fmt, dstWidth, dstHeight, 1); uint8_t *frameBuffer = av_malloc(frameSize); if (frameBuffer == NULL) { av_log(NULL, AV_LOG_ERROR, "av_malloc failed\n"); av_frame_free(&frame); avcodec_free_context(&encodeCtx); fclose(inFp); fclose(destFp); return -1; } av_image_fill_arrays(frame->data, frame->linesize, frameBuffer, pix_fmt, dstWidth, dstHeight, 1); frame->format = pix_fmt; frame->width = dstWidth; frame->height = dstHeight; int pictureSize = dstWidth * dstHeight; AVPacket *packet = av_packet_alloc(); if (packet==NULL){ av_frame_free(&frame); avcodec_free_context(&encodeCtx); fclose(inFp); fclose(destFp); return -1; } int readFrameCount = 0; while (fread(frameBuffer, 1, pictureSize * 3 / 2, inFp) == pictureSize * 3 / 2) { frame->data[0] = frameBuffer; frame->data[1] = frameBuffer + pictureSize; frame->data[2] = frameBuffer + pictureSize + pictureSize / 4; frame->pts = readFrameCount; readFrameCount++; av_log(NULL,AV_LOG_INFO,"read frame index = %d\n",readFrameCount); encodeVideo(encodeCtx, frame, packet, destFp); } encodeVideo(encodeCtx, NULL, packet, destFp); avcodec_free_context(&encodeCtx); fclose(inFp); fclose(destFp); av_frame_free(&frame); av_freep(&frameBuffer); av_packet_free(&packet); 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 -lswscale all:$(TARGET) $(TARGET):$(SRC) $(CC) $(SRC) $(CFLAGS) $(LDFLAGS) -o $(TARGET) clean: rm -rf $(TARGET) rm -rf ../output*