使用FFmpeg实现的转码器
来源:互联网 发布:深入浅出python豆瓣 编辑:程序博客网 时间:2024/05/19 03:23
头文件
#include "stdafx.h"#include <windows.h>extern "C" { #include <libavcodec/avcodec.h> #include <libavdevice/avdevice.h> #include <libavformat/avformat.h> #include <libavfilter/avfilter.h> #include <libavutil/avutil.h> #include <libswscale/swscale.h>#include <stdlib.h> #include <stdio.h> #include <string.h> #include <math.h>} class rtsp2mp4{public: int inputFile(char *file); int outputFile(char *file); int transStart(); int decode(); int encode(); int transEnd();private: int init(); int unit(); int prepare(); int rtsp2mp4 :: flush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index); void ResolutionChange(AVCodecContext *pCodecCtx,AVFrame *pFrame,AVFrame *pNewFrame,int pNewWidth,int pNewHeight); AVFormatContext *in_fmt_ctx; AVStream *in_video_stream; AVFrame *frame; AVFormatContext *out_fmt_ctx; AVStream *out_video_stream; char *rtsp_url; char *name_path; int width; int height; int64_t pts, dts; int last_pts; int last_dts; int video_index; int got_frame; int got_picture; int frame_index; int i;};
具体函数实现
#include "rtsp2mp4.h"/*卸载函数:释放内存*/int rtsp2mp4 :: unit(){ if (out_fmt_ctx && !(out_fmt_ctx->oformat->flags & AVFMT_NOFILE)) { avio_close(out_fmt_ctx->pb); } avcodec_close(out_fmt_ctx->streams[0]->codec); av_freep(&out_fmt_ctx->streams[0]->codec); av_freep(&out_fmt_ctx->streams[0]); avformat_free_context(in_fmt_ctx); avformat_free_context(out_fmt_ctx); return 0;}/*输入读取文件的地址,这是读取的是rtsp流地址,在之后的进行一点修改就可以转码普通格式*/int rtsp2mp4 :: inputFile(char *file){ rtsp_url = file; return 0;}/*输出文件名*/int rtsp2mp4 :: outputFile(char *file){ name_path = file; return 0;}/*FFmpeg组件的注册与一些初始化操作*/int rtsp2mp4 :: init(){ av_register_all(); avformat_network_init(); in_fmt_ctx = NULL; out_fmt_ctx = NULL; width = 800; height = 600; video_index = -1; pts = -3600; dts = -3600; i = 0; frame_index = 0; return 0;}/*准备和一些参数的设定*/int rtsp2mp4 :: prepare(){ int ret = 0; /*下面四行为rtsp流通过TCP协议读取的操作*/ AVDictionary *avdic=NULL; char option_key[]="rtsp_transport"; char option_value[]="tcp"; av_dict_set(&avdic,option_key,option_value,0); /*如果输入的不是rtsp流地址,把avformat_open_input(&in_fmt_ctx,rtsp_url,NULL,&avdic)改为:avformat_open_input(&in_fmt_ctx,rtsp_url,NULL,NULL);*/ if(ret = avformat_open_input(&in_fmt_ctx,rtsp_url,NULL,&avdic) < 0) { printf("无法打开文件\n"); return ret; } if(ret = avformat_find_stream_info(in_fmt_ctx,0) < 0) { printf("无法找到流信息\n"); return ret; } av_dump_format(in_fmt_ctx,0,rtsp_url,0); for(unsigned i =0;i < in_fmt_ctx->nb_streams;i ++) { if(in_fmt_ctx->streams[i]->codec->coder_type == AVMEDIA_TYPE_VIDEO) { in_video_stream = in_fmt_ctx->streams[i]; video_index = i; break; } } /*寻找与打开解码器*/ if(0 > avcodec_open2(in_video_stream->codec, avcodec_find_decoder(in_video_stream->codec->codec_id), NULL)) { printf("无法找到解码器\n"); } /*创建输出文件*/ avformat_alloc_output_context2(&out_fmt_ctx,NULL,NULL,name_path); if(!out_fmt_ctx) { printf("不能创建输出文件\n"); ret = AVERROR_UNKNOWN; return ret; } /*创建输出流*/ out_video_stream = avformat_new_stream(out_fmt_ctx, NULL); if (!out_video_stream) { printf("无法创造新流\n"); ret = AVERROR_UNKNOWN; return ret; } /*参数设置—开始*/ out_video_stream->codec->codec = avcodec_find_encoder(out_fmt_ctx->oformat->video_codec); out_video_stream->codec->height = height; out_video_stream->codec->width = width; out_video_stream->codec->time_base.num = in_fmt_ctx->streams[i]->avg_frame_rate.den; out_video_stream->codec->time_base.den = in_fmt_ctx->streams[i]->avg_frame_rate.num; out_video_stream->codec->sample_aspect_ratio = in_video_stream->codec->sample_aspect_ratio; out_video_stream->codec->pix_fmt = in_video_stream->codec->pix_fmt; out_video_stream->codec->pix_fmt = out_video_stream->codec->codec->pix_fmts[0]; out_video_stream->codec->bit_rate = 500000; out_video_stream->codec->codec_type = AVMEDIA_TYPE_VIDEO; /*按照命令输出的文件修改*/ out_video_stream->codec->thread_count = 6; out_video_stream->codec->max_b_frames = 3; out_video_stream->codec->b_frame_strategy = 1; out_video_stream->codec->gop_size = 250; out_video_stream->codec->keyint_min = 25; out_video_stream->codec->trellis = 1; out_video_stream->codec->me_subpel_quality = 7; out_video_stream->codec->refs = 3; out_video_stream->codec->me_method = ME_HEX; out_video_stream->codec->coder_type = FF_CODER_TYPE_AC; out_video_stream->codec->me_range = 16; out_video_stream->codec->max_qdiff = 4; out_video_stream->codec->qmin = 0; out_video_stream->codec->qmax = 69; out_video_stream->codec->qcompress = 0.6; out_video_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER; /*参数设置—结束*/ /*寻找编码器*/ if (!out_video_stream->codec->codec) { printf("找不到编码器\n"); ret = AVERROR_UNKNOWN; return ret; } AVDictionary *param = 0; av_dict_set(¶m, "profile", "baseline", 0); av_opt_set(out_video_stream->codec->priv_data, "preset", "fast", 0); av_opt_set(out_video_stream->codec->priv_data, "tune", "zerolatency", 0); /*打开编码器*/ if ((avcodec_open2(out_video_stream->codec, out_video_stream->codec->codec, NULL)) < 0) { printf("无法打开编码器\n"); ret = AVERROR_UNKNOWN; return ret; } if(video_index == -1) { printf("没找到视频流\n"); ret = AVERROR_UNKNOWN; return ret; } return 0;}/*转码之前的准备,写头文件等*/int rtsp2mp4 :: transStart(){ init(); prepare(); avio_open(&out_fmt_ctx->pb,name_path,AVIO_FLAG_WRITE); AVDictionary *opt = NULL; av_dict_set_int(&opt,"video_track_timescale",25,0); avformat_write_header(out_fmt_ctx,&opt); return 0;}/*解码一帧*/int rtsp2mp4 :: decode(){ AVFrame *old_frame; old_frame = av_frame_alloc(); frame = av_frame_alloc(); int size = avpicture_get_size(out_video_stream->codec->pix_fmt, width,height); uint8_t* frame_buf = (uint8_t *)av_malloc(size); avpicture_fill((AVPicture *)frame, frame_buf, out_video_stream->codec->pix_fmt, width, height); frame->format = AV_PIX_FMT_YUV420P; frame->width = width; frame->height = height; AVPacket *pkt_in = NULL; int y_size = out_video_stream->codec->width * out_video_stream->codec->height; pkt_in = (AVPacket *)av_malloc(sizeof(AVPacket)); av_new_packet(pkt_in, y_size); int ret = 0; got_frame = -1; if (av_read_frame(in_fmt_ctx, pkt_in) < 0) { av_frame_free(&frame); av_frame_free(&old_frame); ret = AVERROR_UNKNOWN; av_free_packet(pkt_in); return ret; } if(pkt_in->stream_index == video_index) { if (avcodec_decode_video2(in_fmt_ctx->streams[video_index]->codec, old_frame, &got_frame, pkt_in) < 0) { av_frame_free(&frame); av_frame_free(&old_frame); av_free_packet(pkt_in); printf("无法解码\n"); ret = AVERROR_UNKNOWN; return ret; } } printf("got_frame:%d\n",got_frame); av_free_packet(pkt_in); if(got_frame > 0) { ResolutionChange(in_fmt_ctx->streams[video_index]->codec,old_frame,frame,width,height); } av_frame_free(&old_frame); return ret;}/*编码一帧*/int rtsp2mp4 :: encode(){ AVPacket pkt_out; av_init_packet(&pkt_out); int ret = 0; got_picture = -1; if (got_frame > 0) { frame->pts = i++; pkt_out.data = NULL; pkt_out.size = 0; if (avcodec_encode_video2(out_video_stream->codec, &pkt_out, frame, &got_picture) < 0) { av_free_packet(&pkt_out); av_frame_free(&frame); printf("无法编码\n"); ret = AVERROR_UNKNOWN; return ret; } if (got_picture > 0) { printf("成功编码 %5d\t大小:%5d\n",frame_index,pkt_out.size); printf("dts:%10d\tpts:%6d\n",pkt_out.dts,pkt_out.pts); frame_index++; av_write_frame(out_fmt_ctx, &pkt_out); av_free_packet(&pkt_out); } } av_free_packet(&pkt_out); av_frame_free(&frame); return ret;}/*释放内存内的帧并且写尾文件*/int rtsp2mp4 :: transEnd(){ int ret = flush_encoder(out_fmt_ctx, video_index); if (ret < 0) { printf("释放失败\n"); return -1; } avformat_close_input(&in_fmt_ctx); av_write_trailer(out_fmt_ctx); unit(); return 0;}int rtsp2mp4 :: flush_encoder(AVFormatContext *fmt_ctx, unsigned int stream_index){ int ret; int got_frame; AVPacket enc_pkt; if (!(fmt_ctx->streams[stream_index]->codec->codec->capabilities &CODEC_CAP_DELAY)) { return 0; } while(1) { enc_pkt.data = NULL; enc_pkt.size = 0; av_init_packet(&enc_pkt); ret = avcodec_encode_video2(fmt_ctx->streams[stream_index]->codec, &enc_pkt, NULL, &got_frame); av_frame_free(NULL); if (ret < 0) { break; } if (!got_frame) { ret = 0; break; } printf("释放编码数据: 成功编码 1 帧!\tsize:%5d\n",enc_pkt.size); ret = av_write_frame(fmt_ctx, &enc_pkt); if (ret < 0) break; } return ret;}void rtsp2mp4 :: ResolutionChange(AVCodecContext *pCodecCtx,AVFrame *pFrame,AVFrame *pNewFrame,int pNewWidth,int pNewHeight){ pNewFrame->linesize[0] = pNewWidth; pNewFrame->linesize[1] = pNewWidth/2; pNewFrame->linesize[2] = pNewWidth/2; //用 sws_getContext函数 得到 sws_scale函数 运行的上下文,之后用 sws_scale函数 将图形缩放 struct SwsContext *pSwsCtx = NULL; pSwsCtx = sws_getContext(pCodecCtx->width,pCodecCtx->height,AV_PIX_FMT_YUV420P,pNewWidth,pNewHeight,AV_PIX_FMT_YUV420P,SWS_SINC,NULL,NULL,NULL); if(pSwsCtx == NULL) return ; sws_scale(pSwsCtx,pFrame->data,pFrame->linesize,0,pCodecCtx->height,pNewFrame->data,pNewFrame->linesize); sws_freeContext(pSwsCtx);}
0 0
- 使用FFmpeg实现的转码器
- 使用FFmpeg实现视频的裁剪,不需要调用JNI实现
- ffmpeg和ffserver配合使用实现实时的流媒体服务
- 使用PHP调用系统命令实现ffmpeg的调用
- 使用ffmpeg实现RTMP的直播推流功能
- 使用ffmpeg实现视频连接
- 使用ffmpeg实现视频连接
- (转贴)ffmpeg的使用
- [转载]ffmpeg的使用
- ffmpeg的使用
- ffmpeg的使用
- ffmpeg的API使用
- ffmpeg的使用
- ffmpeg的使用
- FFmpeg 工具的使用
- ffmpeg的使用
- ffmpeg使用的问题
- ffmpeg的使用
- iOS 用本地文件保存自定义模型
- 使用webpack 使用Echarts3简单入门
- c#客户端Json转dataTable
- eclipse jni (C/C++)代码提示
- Python & PyCharm & Django 搭建web开发环境
- 使用FFmpeg实现的转码器
- 在Centos7下源码安装配置Redis
- Android加载大图Bitmap发生OOM(Out Of Memmory Error)解决方案
- Android 一起来封装一个简单易用的Adapter
- JavaScript变量、作用域、内存、垃圾回收
- 播放音频文件
- Android源码编译(2)----建立编译环境
- 剑指offer——查找一个字符串中第一次出现一次的字符(哈希直接定址法)
- LIB和DLL的区别与使用