ffmpeg转码多路输出(二)
本程序支持一路输入多路输出,可根据map配置自行添加,第1路为纯拷贝,其他2路经过编解码,格式转换缩放和重采样,纯拷贝方面不同格式适应方面还没做全,以后补充。本程序适合多分辨率切换等方面内容。注意重采样等方面的注释内容。
具体看代码:
//main.cpp
[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
#include "ffmpeg_transcode.h"

/*
int main()
{
AVOutputFormat *ofmt = NULL;
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
AVPacket pkt;
int ret, i;
av_register_all();

if ((ret = avformat_open_input(&ifmt_ctx, INPUTURL, 0, 0)) < 0) {
fprintf(stderr, "Could not open input file '%s'", INPUTURL);
}

if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
fprintf(stderr, "Failed to retrieve input stream information");
}

av_dump_format(ifmt_ctx, 0, INPUTURL, 0);

avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, OUTPUTURL);
if (!ofmt_ctx) {
fprintf(stderr, "Could not create output context\n");
ret = AVERROR_UNKNOWN;
}

ofmt = ofmt_ctx->oformat;

for (i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *in_stream = ifmt_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
if (!out_stream) {
fprintf(stderr, "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
}

ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
if (ret < 0) {
fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
}
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}

if (!(ofmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, OUTPUTURL, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open output file '%s'", OUTPUTURL);
}
}

ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
}

av_dump_format(ofmt_ctx, 0, OUTPUTURL, 1);

AVBitStreamFilterContext * m_vbsf_aac_adtstoasc; //aac->adts to asc过滤器
m_vbsf_aac_adtstoasc = av_bitstream_filter_init("aac_adtstoasc");

while (1)
{
AVStream *in_stream, *out_stream;

ret = av_read_frame(ifmt_ctx, &pkt);
if (ret < 0)
break;

in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];

pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;

if (in_stream->codec->codec_type == AVMEDIA_TYPE_AUDIO)
{
if (m_vbsf_aac_adtstoasc != NULL)
{
AVPacket filteredPacket = pkt;
int a = av_bitstream_filter_filter(m_vbsf_aac_adtstoasc,
out_stream->codec, NULL,&filteredPacket.data, &filteredPacket.size,
pkt.data, pkt.size, pkt.flags & AV_PKT_FLAG_KEY);
if (a > 0)
{
av_free_packet(&pkt);
filteredPacket.destruct = av_destruct_packet;
pkt = filteredPacket;
}
else if (a == 0)
{
pkt = filteredPacket;
}
else if (a < 0)
{
fprintf(stderr, "%s failed for stream %d, codec %s",
m_vbsf_aac_adtstoasc->filter->name,pkt.stream_index,out_stream->codec->codec ? out_stream->codec->codec->name : "copy");
av_free_packet(&pkt);

}
}
}
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
if (ret < 0)
{
break;
}

av_packet_unref(&pkt);
}

av_write_trailer(ofmt_ctx);

avformat_close_input(&ifmt_ctx);

if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
{
avio_closep(&ofmt_ctx->pb);
}
avformat_free_context(ofmt_ctx);
}
*/

int main(int argc ,char ** argv)
{
int ret = 0;

av_register_all();
avformat_network_init();

ffmpeg_init_demux(INPUTURL,&m_icodec);

//out_stream1 用原始的
Out_stream_info *out_stream_info1 = NULL;
out_stream_info1 = new Out_stream_info();
out_stream_info1->user_stream_id = 10;
sprintf(out_stream_info1->m_outurlname,"%s",OUTPUTURL10);
//out_stream2
Out_stream_info *out_stream_info2 = NULL;
out_stream_info2 = new Out_stream_info();
out_stream_info2->user_stream_id = 11;
sprintf(out_stream_info2->m_outurlname,"%s",OUTPUTURL11);
out_stream_info2->m_dwWidth = 640;
out_stream_info2->m_dwHeight = 480;
out_stream_info2->m_dbFrameRate = 25;
out_stream_info2->m_video_codecID = (int)AV_CODEC_ID_H264;
out_stream_info2->m_video_pixelfromat = (int)AV_PIX_FMT_YUV420P;
out_stream_info2->m_bit_rate = 800000;
out_stream_info2->m_gop_size = 125;
out_stream_info2->m_max_b_frame = 0;
out_stream_info2->m_thread_count = 8;
out_stream_info2->m_dwChannelCount = 2;
out_stream_info2->m_dwBitsPerSample = AV_SAMPLE_FMT_S16_t;
out_stream_info2->m_dwFrequency = 44100;
out_stream_info2->m_audio_codecID = (int)AV_CODEC_ID_AAC;
//out_stream3
Out_stream_info *out_stream_info3 = NULL;
out_stream_info3 = new Out_stream_info();
out_stream_info3->user_stream_id = 12;
sprintf(out_stream_info3->m_outurlname,"%s",OUTPUTURL12);
out_stream_info3->m_dwWidth = 352;
out_stream_info3->m_dwHeight = 288;
out_stream_info3->m_dbFrameRate = 25;
out_stream_info3->m_video_codecID = (int)AV_CODEC_ID_H264;
out_stream_info3->m_video_pixelfromat = (int)AV_PIX_FMT_YUV420P;
out_stream_info3->m_bit_rate = 400000;
out_stream_info3->m_gop_size = 125;
out_stream_info3->m_max_b_frame = 0;
out_stream_info3->m_thread_count = 8;
out_stream_info3->m_dwChannelCount = 2;
out_stream_info3->m_dwBitsPerSample = AV_SAMPLE_FMT_S16_t;
out_stream_info3->m_dwFrequency = 44100;
out_stream_info3->m_audio_codecID = (int)AV_CODEC_ID_AAC;

//申请map
m_list_out_stream_info[out_stream_info1->user_stream_id] = (out_stream_info1);
m_list_out_stream_info[out_stream_info2->user_stream_id] = (out_stream_info2);
m_list_out_stream_info[out_stream_info3->user_stream_id] = (out_stream_info3);

ffmpeg_init_mux(m_list_out_stream_info,out_stream_info1->user_stream_id);
printf("--------程序运行开始----------\n");
//////////////////////////////////////////////////////////////////////////
ffmpeg_transcode(out_stream_info1->user_stream_id);
//////////////////////////////////////////////////////////////////////////
ffmpeg_uinit_mux(m_list_out_stream_info,out_stream_info1->user_stream_id);
ffmpeg_uinit_demux(m_icodec);

//释放map
if (m_list_out_stream_info.size()> 0)
{
map<int,Out_stream_info*> ::iterator result_all;
Out_stream_info * out_stream_info_all = NULL;
for (result_all = m_list_out_stream_info.begin();result_all != m_list_out_stream_info.end();)
{
out_stream_info_all = result_all->second;
if(out_stream_info_all)
{
delete out_stream_info_all;
out_stream_info_all = NULL;
}
m_list_out_stream_info.erase(result_all ++);
}
m_list_out_stream_info.clear();
}
printf("--------程序运行结束----------\n");
printf("-------请按任意键退出---------\n");
return getchar();
}

//.h
[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
#ifndef __FFMPEG_TRANSCODE_H__
#define __FFMPEG_TRANSCODE_H__

#include <string.h>
#include <stdio.h>
#include <vector>
#include <map>
#include <list>

using namespace std;

extern "C"
{
#include "libavformat/avformat.h"
#include "libavformat/avio.h"
#include "libavcodec/avcodec.h"
#include "libswscale/swscale.h"
#include "libavutil/avutil.h"
#include "libavutil/mathematics.h"
#include "libswresample/swresample.h"
#include "libavutil/opt.h"
#include "libavutil/channel_layout.h"
#include "libavutil/samplefmt.h"
#include "libavdevice/avdevice.h" //摄像头所用
#include "libavfilter/avfilter.h"
#include "libavutil/error.h"
#include "libavutil/mathematics.h"
#include "libavutil/time.h"
#include "libavutil/fifo.h"
#include "libavutil/audio_fifo.h" //这里是做分片时候重采样编码音频用的
#include "inttypes.h"
#include "stdint.h"
};

#pragma comment(lib,"avformat.lib")
#pragma comment(lib,"avcodec.lib")
#pragma comment(lib,"avdevice.lib")
#pragma comment(lib,"avfilter.lib")
#pragma comment(lib,"avutil.lib")
#pragma comment(lib,"postproc.lib")
#pragma comment(lib,"swresample.lib")
#pragma comment(lib,"swscale.lib")

//#define INPUTURL "../in_stream/22.flv"
//#define INPUTURL "../in_stream/闪电侠.The.Flash.S01E01.中英字幕.HDTVrip.624X352.mp4"
//#define INPUTURL "../in_stream/33.ts"
//#define INPUTURL "../in_stream/22mp4.mp4"
//#define INPUTURL "../in_stream/EYED0081.MOV"
//#define INPUTURL "../in_stream/李荣浩 - 李白.mp3"
//#define INPUTURL "../in_stream/avier1.mp4"
//#define INPUTURL "../in_stream/分歧者2预告片.mp4"
//#define INPUTURL "../in_stream/Class8简介.m4v"
#define INPUTURL "../in_stream/9160_2.ts"
//#define INPUTURL "../in_stream/44.mp3"
//#define INPUTURL "../in_stream/ceshi.mp4"
//#define INPUTURL "../in_stream/33.mp4"
//#define INPUTURL "../in_stream/father.avi"
//#define INPUTURL "../in_stream/22.flv"
//#define INPUTURL "../in_stream/西海情歌.wav"
//#define INPUTURL "../in_stream/Furious_7_2015_International_Trailer_2_5.1-1080p-HDTN.mp4"
//#define INPUTURL "../in_stream/Wildlife.wmv"
//#define INPUTURL "../in_stream/单身男女2.HD1280超清国语版.mp4"
//#define INPUTURL "rtmp://221.228.193.50:1935/live/teststream1"
#define OUTPUTURL "../out_stream/output.flv"
//http://10.69.112.96:8080/live/10flv/index.m3u8
#define OUTPUTURL10 "../out_stream/10.flv"
//#define OUTPUTURL10 "rtmp://10.69.112.96:1936/live/10flv"
#define OUTPUTURL11 "../out_stream/11.flv"
//#define OUTPUTURL11 "rtmp://10.69.112.96:1936/live/11flv"
#define OUTPUTURL12 "../out_stream/12.flv"
//#define OUTPUTURL12 "rtmp://10.69.112.96:1936/live/12flv"
//#define OUTPUTURL "rtmp://221.228.193.50:1935/live/zwg"
//#define OUTPUTURL "rtmp://221.228.193.50:1935/live/zwg"

//样本枚举
enum AVSampleFormat_t
{
AV_SAMPLE_FMT_NONE_t = -1,
AV_SAMPLE_FMT_U8_t, ///< unsigned 8 bits
AV_SAMPLE_FMT_S16_t, ///< signed 16 bits
AV_SAMPLE_FMT_S32_t, ///< signed 32 bits
AV_SAMPLE_FMT_FLT_t, ///< float
AV_SAMPLE_FMT_DBL_t, ///< double

AV_SAMPLE_FMT_U8P_t, ///< unsigned 8 bits, planar
AV_SAMPLE_FMT_S16P_t, ///< signed 16 bits, planar
AV_SAMPLE_FMT_S32P_t, ///< signed 32 bits, planar
AV_SAMPLE_FMT_FLTP_t, ///< float, planar
AV_SAMPLE_FMT_DBLP_t, ///< double, planar

AV_SAMPLE_FMT_NB_t ///< Number of sample formats. DO NOT USE if linking dynamically
};

#define OUT_AUDIO_ID 0 //packet 中的ID ,如果先加入音频 pocket 则音频是 0 视频是1,否则相反(影响add_out_stream顺序)
#define OUT_VIDEO_ID 1

//多路输出每一路的信息结构体
typedef struct Out_stream_info_t
{
//user info
int user_stream_id; //多路输出每一路的ID
//video param
int m_dwWidth;
int m_dwHeight;
double m_dbFrameRate; //帧率
int m_video_codecID;
int m_video_pixelfromat;
int m_bit_rate; //码率
int m_gop_size;
int m_max_b_frame;
int m_thread_count; //用cpu内核数目
//audio param
int m_dwChannelCount; //声道
AVSampleFormat_t m_dwBitsPerSample; //样本
int m_dwFrequency; //采样率
int m_audio_codecID;

//ffmpeg out pram
AVAudioFifo * m_audiofifo; //音频存放pcm数据
int64_t m_first_audio_pts; //第一帧的音频pts
int m_is_first_www.yuheng119.com/ audio_pts; //是否已经记录第一帧音频时间戳
AVFormatContext* m_ocodec ; //输出流context
int m_writeheader_seccess; //写头成功也就是写的头支持里面填写的音视频格式例如采样率等等
AVStream* m_ovideo_st;
AVStream* m_oaudio_st;
AVCodec * m_audio_codec;
AVCodec * m_video_codec;
AVPacket m_pkt;
AVBitStreamFilterContext * m_vbsf_aac_adtstoasc; //aac->adts to asc过滤器
struct SwsContext * m_img_convert_ctx_video;
int m_sws_flags; //差值算法,双三次
AVFrame * m_pout_video_frame;
AVFrame * m_pout_audio_frame;
SwrContext * m_swr_ctx;
char m_outurlname[256]; //输出的url地址

Out_stream_info_t()
{
//user info
user_stream_id = 0; //多路输出每一路的ID
//video param
m_dwWidth = 640;
m_dwHeight = 480;
m_dbFrameRate = 25; //帧率
m_video_codecID = (int)AV_CODEC_ID_H264;
m_video_pixelfromat = (int)AV_PIX_FMT_YUV420P;
m_bit_rate = 400000; //码率
m_gop_size = 12;
m_max_b_frame = 0;
m_thread_count = 2; //用cpu内核数目
//audio param
m_dwChannelCount = 2; //声道
m_dwBitsPerSample = AV_SAMPLE_FMT_S16_t; //样本
m_dwFrequency = 44100; //采样率
m_audio_codecID = http://027yeshenghuowang.com/(int)AV_CODEC_ID_AAC;

//ffmpeg out pram
m_audiofifo = NULL; //音频存放pcm数据
m_first_audio_pts = 0; //第一帧的音频pts
m_is_first_audio_pts = 0; //是否已经记录第一帧音频时间戳
m_ocodec = NULL; //输出流context
m_writeheader_seccess = 0;
m_ovideo_st = NULL;
m_oaudio_st = NULL;
m_audio_codec = NULL;
m_video_codec = NULL;
//m_pkt;
m_vbsf_aac_adtstoasc = NULL; //aac->adts to asc过滤器
m_img_convert_ctx_video = NULL;
m_sws_flags = SWS_BICUBIC; //差值算法,双三次
m_pout_video_frame = NULL;
m_pout_audio_frame = NULL;
m_swr_ctx = NULL;
memset(m_outurlname,0,256); //清零
}
}Out_stream_info;

extern AVFormatContext* m_icodec; //输入流context
extern int m_in_dbFrameRate; //输入流的帧率
extern int m_in_video_stream_idx; //输入流的视频序列号
extern int m_in_audio_stream_idx; //输入流的音频序列号
extern int m_in_video_starttime; //输入流的视频起始时间
extern int m_in_audio_starttime; //输入流的音频起始时间
extern AVPacket m_in_pkt; //读取输入文件packet
extern map<int,Out_stream_info*> m_list_out_stream_info; //多路输出的list

//初始化demux
int ffmpeg_init_demux(char * inurlname,AVFormatContext ** iframe_c);
//释放demux
int ffmpeg_uinit_demux(AVFormatContext * iframe_c);
//初始化mux:list,原始流只需要copy的
int ffmpeg_init_mux(map<int,Out_stream_info*> list_out_stream_info,int original_user_stream_id);
//释放mux,原始流只需要copy的不用打开编码器
int ffmpeg_uinit_mux(map<int,Out_stream_info*> list_out_stream_info,int original_user_stream_id);

//for mux copy
AVStream * ffmpeg_add_out_stream(AVFormatContext* output_format_context,www.xyseo.net AVMediaType codec_type_t);
//for codec
AVStream * ffmpeg_add_out_stream2(Out_stream_info * out_stream_info,AVMediaType codec_type_t,AVCodec **codec);
int ffmpeg_init_decode(int stream_type);
int ffmpeg_init_code(int stream_type,AVStream* out_stream,AVCodec * out_codec);
int ffmpeg_uinit_decode(int stream_type);
int ffmpeg_uinit_code(int stream_type,AVStream* out_stream);
//转码数据,原始流只需要copy的
int ffmpeg_transcode(int original_user_stream_id);

//下面是转码数据里面用的
int ffmpeg_perform_decode(int stream_type,AVFrame * picture);
int ffmpeg_perform_code2(Out_stream_info * out_stream_info,int stream_type,AVFrame * picture); //用于AVAudioFifo
void ffmpeg_perform_yuv_conversion(Out_stream_info * out_stream_info,AVFrame * pinframe,AVFrame * poutframe);
SwrContext * ffmpeg_init_pcm_resample(Out_stream_info * out_stream_info,AVFrame *in_frame, AVFrame *out_frame);
int ffmpeg_preform_pcm_resample(Out_stream_info * out_stream_info,SwrContext * www.yigouyl688.cn pSwrCtx,AVFrame *in_frame, AVFrame *out_frame);
void ffmpeg_uinit_pcm_resample(SwrContext * swr_ctx,AVAudioFifo * audiofifo);
void ffmpeg_write_frame(Out_stream_info * out_stream_info,int ID,AVPacket pkt_t); //copy
void ffmpeg_write_frame2(Out_stream_info * out_stream_info,int ID,AVPacket pkt_t); //codec

ffmpeg转码多路输出(二)的更多相关文章

  1. phpqrcode不能输出二维码

    phpqrcode不能输出二维码  注意 权限.....  注意 扩展 header('Content-Type: image/png'); include_once 'phpqrcode/qrlib ...

  2. 最新版ffmpeg源码分析

    最新版ffmpeg源码分析一:框架 (ffmpeg v0.9) 框架 最新版的ffmpeg中发现了一个新的东西:avconv,而且ffmpeg.c与avconv.c一个模样,一研究才发现是libav下 ...

  3. ffmpeg转码器移植VC的工程:ffmpeg for MFC

    本文介绍一个自己做的FFMPEG移植到VC下的开源工程:ffmpeg for MFC.本工程将ffmpeg工程中的ffmpeg转码器(ffmpeg.c)移植到了VC环境下.并且使用MFC做了一套简单的 ...

  4. ffmpeg转码器移植VC的project:ffmpeg for MFC

    本文介绍一个自己做的FFMPEG移植到VC下的开源project:ffmpeg for MFC.本project将ffmpegproject中的ffmpeg转码器(ffmpeg.c)移植到了VC环境下 ...

  5. 【原】FMDB源码阅读(二)

    [原]FMDB源码阅读(二) 本文转载请注明出处 -- polobymulberry-博客园 1. 前言 上一篇只是简单地过了一下FMDB一个简单例子的基本流程,并没有涉及到FMDB的所有方方面面,比 ...

  6. 微信支付Native扫码支付模式二之CodeIgniter集成篇

    CI:3.0.5 微信支付API类库来自:https://github.com/zhangv/wechat-pay 请先看一眼官方场景及支付时序图:https://pay.weixin.qq.com/ ...

  7. 修改FFMpeg源码—捕获丢包

    概述 最近我们项目有一个需求就是解决客户端播放RTSP视频流花屏的问题,一般来说丢包就会引起花屏,导致客户端花屏的因素又有很多,比如说: 相机到服务器丢包 服务器到客户端丢包 等等... 其中服务器到 ...

  8. FFmpeg源码结构图 - 解码

    ===================================================== FFmpeg的库函数源码分析文章列表: [架构图] FFmpeg源码结构图 - 解码 FFm ...

  9. 一个普通的 Zepto 源码分析(二) - ajax 模块

    一个普通的 Zepto 源码分析(二) - ajax 模块 普通的路人,普通地瞧.分析时使用的是目前最新 1.2.0 版本. Zepto 可以由许多模块组成,默认包含的模块有 zepto 核心模块,以 ...

随机推荐

  1. css 多行文本以...代替

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. FFmpeg内存操作(三)内存转码器

    相关博客列表 : FFMPEG内存操作(一) avio_reading.c 回调读取数据到内存解析 FFMPEG内存操作(二)从内存中读取数及数据格式的转换 FFmpeg内存操作(三)内存转码器 本文 ...

  3. java基础回顾之IO

    Java的IO 是Java运用重要部分之一,涉及到的内容也比较多,容易混淆,一段时间不用,可能就会遗忘,要时常回顾记忆一下: (图片来源于网络) Java 流在处理上分为字符流和字节流. 字符流处理的 ...

  4. LeetCode:Add Digits - 非负整数各位相加

    1.题目名称 Add Digits (非负整数各位相加) 2.题目地址 https://leetcode.com/problems/add-digits/ 3.题目内容 英文:Given a non- ...

  5. [Ural1099]工作安排 带花树

    题目大意 一般图最大匹配. 题解: 求解一般图最大匹配. 直接使用带花树即可. (带花树也是刚学)... 马上写带花树的ppt,会很通俗易懂. (充分证明了本苣智商不够,写不出高深的课件) 如果有想要 ...

  6. Java中String和byte[]间的 转换

    数据库的字段中使用了blob类型时,在entity中此字段可以对应为byte[] 类型,保存到数据库中时需要把传入的参数转为byte[]类型,读取的时候再通过将byte[]类型转换为String类型. ...

  7. C#如何对DataTable中的数据进行条件搜索

    经常遇到将数据库中的数据读取到DataTable中的时候再次对DataTable进行条件筛选,下面的筛选的一个例子: DataRow[] dr = dt.Select("token = '& ...

  8. Python-IO模式介绍

    事件驱动模型:有个事件队列,把事件放到队列里,然后循环这个队列,取出事件执行 5种IO模式: 阻塞 I/O(blocking IO) 非阻塞 I/O(nonblocking IO) I/O 多路复用( ...

  9. JAVA基础知识总结3(面向对象)

    特点:过程其实就是函数:对象是将函数等一些内容进行了封装 1:将复杂的事情简单化. 2:面向对象将以前的过程中的执行者,变成了指挥者. 3:面向对象这种思想是符合现在人们思考习惯的一种思想. 匿名对象 ...

  10. 项目一:第七天 CRM 和bos系统实现定区关联客户,关联快递员. 通过CXF框架实现

    定区关联客户 需求:为了快递方便客户下订单(发快递),派快递员上门取件.  所以说需要让定区关联客户(知道客户属于哪个定区),定区跟快递员关系:多对多.知道让哪个快递员上门取件. 将CRM系统中,客户 ...