使用ffmpeg3.x进行YUV420P->H.264的简单转码
来源:互联网 发布:tcp20端口和21端口 编辑:程序博客网 时间:2024/06/03 13:57
本文代码是基于雷霄骅的《最简单的基于FFMPEG的视频编码器(YUV编码为H.264)》一文修改得来的。
由于雷霄骅原文中采用的API在新版本ffmpeg中,关健的编码API发生了变化,我在此基础上,参考了ffmpeg3.x的sample和header修改后得到。
主要的变化是在编码API上,原来是通过avcodec_encode_video2()来完成编码的,现在编码API变为avcodec_send_frame()/avcodec_receive_packet()组合。
avcodec_send_frame()顾名词义就是发送一帧去编码。avcodec_receive_packet()是吐出来的编码包,写到文件中就是H.264数据了。
另外我也是初学者,对个别编码参数的含义还没有完全搞懂,还有就是在将所有帧编码写入文件后,最后为什么要flush一下,也还没有搞明白,相信以后我会知道答案的^_^
以下代码在vs 2013上跑通,ffmpeg来自:ffmpeg-20170525-b946bd8-win32-dev
extern "C"{#include "libavutil/opt.h"#include "libavcodec/avcodec.h"#include "libavformat/avformat.h"#include "libavutil/imgutils.h"};//encode one framestatic int encode(AVCodecContext *pCodecCtx, AVFrame *pFrame, AVPacket *pPkt, FILE *out_file) { int got_packet = 0; int ret = avcodec_send_frame(pCodecCtx, pFrame); if (ret < 0) { //failed to send frame for encoding return -1; } while (!ret) { ret = avcodec_receive_packet(pCodecCtx, pPkt); if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) { return 0; }else if (ret < 0) { //error during encoding return -1; } printf("Write frame %d, size=%d\n", pPkt->pts, pPkt->size); fwrite(pPkt->data, 1, pPkt->size, out_file); av_packet_unref(pPkt); } return 0;}int _tmain(int argc, _TCHAR* argv[]){ AVFormatContext *pFormatCtx; AVOutputFormat *pOutputFmt; AVStream *pStream; AVCodecContext *pCodecCtx; AVCodec *pCodec; AVPacket *pkt; AVFrame *pFrame; FILE *in_file = NULL, *out_file = NULL; in_file = fopen("ds_480x272.yuv", "rb"); if (in_file == NULL){ printf("cannot open in file\n"); goto OUT; } int in_w = 480, in_h = 272; int nFrameNum = 100; out_file = fopen("out.h264", "wb"); if (out_file == NULL) { printf("cannot create out file\n"); goto OUT; } uint8_t* pFrameBuf = NULL; int frame_buf_size = 0; int y_size = 0; int nEncodedFrameCount = 0; uint8_t endcode[] = { 0, 0, 1, 0xb7 }; av_register_all(); pFormatCtx = avformat_alloc_context(); pOutputFmt = av_guess_format(NULL, "test.h264", NULL); pFormatCtx->oformat = pOutputFmt; //除了以下方法,另外还可以使用avcodec_find_encoder_by_name()来获取AVCodec pCodec = avcodec_find_encoder(pOutputFmt->video_codec); if (!pCodec) { //cannot find encoder return -1; } pCodecCtx = avcodec_alloc_context3(pCodec); if (!pCodecCtx) { //failed get AVCodecContext return -1; } pkt = av_packet_alloc(); if (!pkt){ return -1; } //pCodecCtx = pStream->codec; pCodecCtx->codec_id = pOutputFmt->video_codec; pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO; pCodecCtx->pix_fmt = AV_PIX_FMT_YUV420P; pCodecCtx->width = in_w; pCodecCtx->height = in_h; pCodecCtx->time_base.num = 1; pCodecCtx->time_base.den = 25; //pCodecCtx->time_base = (AVRational){ 1, 25 }; pCodecCtx->bit_rate = 400000; //??? pCodecCtx->gop_size = 250; //??? //pCodecCtx->framerate = (AVRational){ 25, 1 }; //H264 //pCodecCtx->me_range = 16; //??? //pCodecCtx->max_qdiff = 4; //??? //pCodecCtx->qcompress = 0.6; //??? pCodecCtx->qmin = 10; //??? pCodecCtx->qmax = 51; //??? //Optional Param pCodecCtx->max_b_frames = 3; //Set Option AVDictionary *param = NULL; //H.264 if (pCodecCtx->codec_id == AV_CODEC_ID_H264) { av_dict_set(¶m, "preset", "slow", 0); av_dict_set(¶m, "tune", "zerolatency", 0); //av_dict_set(¶m, "profile", "main", 0); } //H.265 if (pCodecCtx->codec_id == AV_CODEC_ID_H265) { av_dict_set(¶m, "preset", "ultrafast", 0); av_dict_set(¶m, "tune", "zero-latency", 0); } if (avcodec_open2(pCodecCtx, pCodec, ¶m) < 0) { //failed to open codec return -1; } pFrame = av_frame_alloc(); if (!pFrame) { fprintf(stderr, "Could not allocate the video frame data\n"); goto OUT; } pFrame->format = pCodecCtx->pix_fmt; pFrame->width = pCodecCtx->width; pFrame->height = pCodecCtx->height; int ret = av_frame_get_buffer(pFrame, 32); if (ret < 0) { fprintf(stderr, "Could not allocate the video frame data\n"); goto OUT; } frame_buf_size = av_image_get_buffer_size(pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 1); pFrameBuf = (uint8_t*)av_malloc(frame_buf_size); av_image_fill_arrays(pFrame->data, pFrame->linesize, pFrameBuf, pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, 1); y_size = pCodecCtx->width * pCodecCtx->height; for (int i = 0; i < nFrameNum; i++) { //Read raw YUV data if (fread(pFrameBuf, 1, y_size * 3 / 2, in_file) <= 0) { //failed to read raw YUV data return -1; } else if (feof(in_file)) { break; } ret = av_frame_make_writable(pFrame); if (ret < 0) { goto OUT; } pFrame->data[0] = pFrameBuf; //Y pFrame->data[1] = pFrameBuf + y_size; //U pFrame->data[2] = pFrameBuf + y_size*5/4; //V //PTS pFrame->pts = i; //encode encode(pCodecCtx, pFrame, pkt, out_file); } //flush the encoder encode(pCodecCtx, NULL, pkt, out_file); //add sequence end code to have a real MPEG file fwrite(endcode, 1, sizeof(endcode), out_file); avcodec_free_context(&pCodecCtx); avformat_free_context(pFormatCtx); av_frame_free(&pFrame); av_packet_free(&pkt); av_free(pFrameBuf);OUT: if (out_file) fclose(out_file); if (in_file) fclose(in_file); system("pause"); return 0;}
阅读全文
0 0
- 使用ffmpeg3.x进行YUV420P->H.264的简单转码
- 使用Android studio移植FFmpeg3.3进行转码
- 使用Android studio移植FFmpeg3.3进行转码
- (ffmpeg3.3.x更新纪要)雷霄骅《最简单的基于FFMPEG+SDL的视频播放器》
- YUV420P的像素数据编码为H.264的压缩编码数据
- 最简单的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)
- 最简单的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)
- 最简单的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)
- 最简单的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)
- 最简单的视音频播放示例6:OpenGL播放YUV420P(通过Texture,使用Shader)
- ffmpeg3
- 使用ffmpeg进行h.264编码
- vitamio5.x的简单使用
- vitamio5.x的简单使用
- Sikuli-X简单的使用
- vitamio5.x的简单使用
- rgb24转yuv420p
- yuv420p转bmp图片
- GAN生成对抗网络
- 编写测试简单的服务器和客户端 (C++)(十一)
- HDU
- BeanUtils使用及其方法分析
- AssetBundle.cs
- 使用ffmpeg3.x进行YUV420P->H.264的简单转码
- Python之ReportLab绘图
- crond和crontab调研
- HDU-1014 Uniform Generator
- JavaScript函数的调用方式和传参方式
- 每日一学(一)android图形验证码的实现
- Python之ReportLab绘制条形码和二维码
- 水池数目
- 2017年6月9日,周结(十六),一些简单的算法题(二)