yuv420转h264
来源:互联网 发布:淘宝管理软件 编辑:程序博客网 时间:2024/05/18 14:15
注意视频的AVCodecContext需要设置哪些参数,还有avcodec_encode_video2编码出来的AVPacket是不是空(部落格它为空,got_packet_ptr为0)和max_b_frames有关。另外视频的flush,和音频转码那篇文章同理。代码中也包含了pts的计算方法
#include <stdio.h>#include <stdint.h>#include <cstring>#include <malloc.h>#include <windows.h>extern "C"{#include "libavcodec/avcodec.h"#include "libavutil/audio_fifo.h"#include "libavformat/avformat.h"#include "libavutil/avstring.h"#include "libswscale/swscale.h"#include "libswresample/swresample.h"#include <libavutil/opt.h>#include <libavutil/channel_layout.h>#include <libavutil/samplefmt.h>};#define STREAM_FRAME_RATE 25#define STREAM_PIX_FMT AV_PIX_FMT_YUV420P const int width = 640, height = 360;int framecount = 0;void init_packet(AVPacket *packet){ av_init_packet(packet); packet->data = NULL; packet->size = 0;}/* add a video output stream */AVStream *add_video_stream(AVFormatContext *out_format_context, AVCodecID codec_id){ AVCodecContext *out_codec_context; AVStream *video_st; video_st = avformat_new_stream(out_format_context, 0);//vido_st的time_base是1/90000 ,avg_frame_rate是0 if (!video_st) { fprintf(stderr, "Could not alloc stream"); exit(1); } out_codec_context = video_st->codec; out_codec_context->codec_id = codec_id; out_codec_context->codec_type = AVMEDIA_TYPE_VIDEO; /* 设置比特率(码率),每秒传输多少bit */ out_codec_context->bit_rate = 400000; /* resolution must be a multiple of two */ out_codec_context->width = width; out_codec_context->height = height; // 设置 25 帧每秒 ,也就是 fps 为 25 out_codec_context->time_base.den = STREAM_FRAME_RATE; out_codec_context->time_base.num = 1; out_codec_context->gop_size = 12; /* //每12帧插入1个I帧,I帧越少,视频越小 */ out_codec_context->pix_fmt = STREAM_PIX_FMT; out_codec_context->qmin = 10; out_codec_context->qmax = 51; /* 最大B帧数,默认是0,它的影响:avcodec_encode_video2 丢失的也就是缓存的帧数(got_packet会为0).这个帧数是固定的并且由最大B帧数决定的. B帧越多,文件越小 */ out_codec_context->max_b_frames = 3; // some formats want stream headers to be separate if (out_format_context->oformat->flags & AVFMT_GLOBALHEADER) out_codec_context->flags |= CODEC_FLAG_GLOBAL_HEADER; return video_st;}void open_video(AVCodecContext* codec_context){ /* find the video encoder */ AVCodec* codec = avcodec_find_encoder(codec_context->codec_id); if (!codec) { fprintf(stderr, "codec not found\n"); exit(1); } AVDictionary *param = NULL; //H.264 if (codec_context->codec_id == AV_CODEC_ID_H264) { // 通过--preset的参数调节编码速度和质量的平衡。 av_dict_set(¶m, "preset", "fast", 0); // 通过--tune的参数值指定片子的类型,是和视觉优化的参数,或有特别的情况。 // zerolatency: 零延迟,用在需要非常低的延迟的情况下,比如电视电话会议的编码 av_dict_set(¶m, "tune", "zerolatency", 0); } /* open the codec */ if (avcodec_open2(codec_context, codec, ¶m) < 0) { fprintf(stderr, "could not open codec\n"); exit(1); }}int encode_video_frame(AVFrame *frame, AVFormatContext *out_format_context, AVStream *video_st){ AVCodecContext* out_codec_context = video_st->codec; int got_packet; AVPacket enc_pkt; init_packet(&enc_pkt); int ret = avcodec_encode_video2(out_codec_context, &enc_pkt, frame, &got_packet); if (ret < 0 || !got_packet){ //在flush的时候,如果失败 ,说明丢失帧(缓存帧)已经空了 av_free_packet(&enc_pkt); av_frame_free(&frame); return 1; } if (enc_pkt.pts == AV_NOPTS_VALUE){ double duration_s = av_q2d(out_codec_context->time_base);//每帧有多少秒(标准时间) double duration = duration_s / av_q2d(video_st->time_base);//AVStream时间基下的格子数 enc_pkt.pts = framecount*duration;//current_pts-pre_pts=current_duration,根据数学公式an=a1+(n-1)*d可得pts=n*d enc_pkt.dts = enc_pkt.pts; printf("pts:%lld\n", enc_pkt.pts); } enc_pkt.stream_index = video_st->index; ret = av_write_frame(out_format_context, &enc_pkt); av_free_packet(&enc_pkt); av_frame_free(&frame); if (ret < 0){ return 1; }else{ framecount++; } return 0;}int main(int argc, char **argv){ av_register_all(); FILE* fp = fopen("sintel_640_360.yuv", "rb"); const char* out_file = "output.h264"; AVOutputFormat* fmt = av_guess_format(NULL, out_file, NULL); if (!fmt) { fprintf(stderr, "Could not find suitable output format"); exit(1); } AVFormatContext* out_format_context = avformat_alloc_context(); out_format_context->oformat = fmt; AVStream *video_st = add_video_stream(out_format_context, fmt->video_codec); //这里video_st的time_base是默认值 1/90000 AVCodecContext* out_codec_context = video_st->codec; open_video(out_codec_context); /* open the output file, if needed */ if (!(fmt->flags & AVFMT_NOFILE)) { if (avio_open(&(out_format_context->pb), out_file, AVIO_FLAG_WRITE) < 0) { fprintf(stderr, "Could not open '%s'\n", out_file); return 1; } } /* write the stream header, if any */ avformat_write_header(out_format_context, NULL); uint8_t *buffer = new uint8_t[avpicture_get_size(out_codec_context->pix_fmt, out_codec_context->width, out_codec_context->height)]; while (1){ int ret = fread(buffer, out_codec_context->width * out_codec_context->height * 3 / 2, 1, fp); if (ret == 0){ break; } AVFrame* yuvFrame = av_frame_alloc(); avpicture_fill((AVPicture *)yuvFrame, buffer, out_codec_context->pix_fmt, out_codec_context->width, out_codec_context->height); encode_video_frame(yuvFrame, out_format_context, video_st); } if (out_codec_context->codec->capabilities &CODEC_CAP_DELAY){ while (!encode_video_frame(NULL, out_format_context, video_st)){ ; } } av_write_trailer(out_format_context); if (video_st){ avcodec_close(video_st->codec); } if (out_codec_context){ avcodec_close(out_codec_context); } if (out_format_context) { avio_closep(&out_format_context->pb); avformat_free_context(out_format_context); } return 0;}
阅读全文
0 0
- yuv420转h264
- H264 YUV420视频翻转
- capture(yuv422) -> h264 encode(yuv420) -> h264 -> h264 decode(yuv420)
- FFmpeg解码H264为YUV420
- linux 摄像头采集图像经过YUYV转YUV420再经过H264编码后通过Socket发送至服务器端
- YUV420转YUV444 , YUV420转RGB
- YUV420转YUV444 , YUV420转RGB
- YUV420转YUV444 , YUV420转RGB
- YUV420转YUV444 , YUV420转RGB
- YUV420转YUV444 , YUV420转RGB .
- rgb转yuv420,yuv420转rgb
- YUV420格式转换为H264 2D格式
- FFMPEG3.2SDK解码H264保存为YUV420文件
- ffmpeg简化方案---只支持h264解码,输出为yuv420
- Live555接收h264使用ffmpeg解码为YUV420
- Live555接收h264使用ffmpeg解码为YUV420 .
- Live555接收h264使用ffmpeg解码为YUV420 .
- Live555接收h264使用ffmpeg解码为YUV420 .
- Android 方面一些参考网页
- 实用工具网址搜集
- 【java学习准备1】一些基本概念
- TCP协议三次握手协议
- Elasticsearch 2.0以上版本根据条件批量删除Java如何实现
- yuv420转h264
- Android输入系统简介
- 如何查看linux硬盘空间
- qt5.1+ vs2013+opencv2.4.8制作视频图片读取界面
- ubuntu下opencv3.1.0+caffe安装教程(CPU-only)
- mysql-主主搭建mm
- VSCode拓展插件推荐(HTML、Node、Vue、React开发均适用)
- ArcGIS for Android 地图控件 mapview 的常见操作
- 两台电脑用一根网线连接组成局域网共享传输文件