如有错误请指正,谢谢。

使用ffmpeg添加rtsp字幕流 (t140)

使用ffmpeg推送一个视频文件到rtsp非常简单:

ffmpeg -re -i subtitle.mkv -vcodec copy -acodec copy -rtsp_transport tcp -f rtsp rtsp://127.0.0.1:10554/sVideo

但如果想要把视频中的字幕流也推送到rtsp服务器上却不行:

ffmpeg -re -i subtitle.mkv -vcodec copy -acodec copy -scodec copy -rtsp_transport tcp -f rtsp rtsp://127.0.0.1:10554/sVideo

提示:
[rtp @ 0503fd00] Unsupported codec ass

所以要使用ffmpeg推送rtsp字幕流必须要修改源码, 关于rtp载荷文本流的协议描述为RFC4103。

  • RFC4103

1.使rtp打包支持subtitle形式的编码

要使rtp打包时支持相关字幕编码器, 必须修改rtpenc.c中的 is_supported函数, 在最后加入AV_CODEC_ID_ASS(ass字幕), AV_CODEC_ID_TEXT(纯文本字幕流)

static int is_supported(enum AVCodecID id)
{switch(id) {case AV_CODEC_ID_DIRAC:case AV_CODEC_ID_H261:...case AV_CODEC_ID_TEXT:case AV_CODEC_ID_ASS:return 1;default:return 0;}
}

2.使创建sdp时生成subtitle相关字段

rtsp对可用媒体流的数量及属性判断是通过SDP, 所以有字幕流的rtsp,需要在创建rtsp时一并将字幕流的信息也创建完成。

修改sdp.c sdp_write_media_attributes函数,指定subtitle编码器对应的流媒体描述。
指定AV_CODEC_ID_TEXT编码器的名称为t140, AV_CODEC_ID_ASS编码器的名称为ass。
ffmpeg解析rtsp的sdp时会根据rtpmap中的编码器名称去寻找对应的编码属性,生成相关的媒体流。

sdp.c:sdp_write_media_attributes 函数修改节选

    switch (p->codec_id) {case AV_CODEC_ID_DIRAC:av_strlcatf(buff, size, "a=rtpmap:%d VC2/90000\r\n", payload_type);break;case AV_CODEC_ID_H264: {int mode = 1;if (fmt && fmt->oformat && fmt->oformat->priv_class &&av_opt_flag_is_set(fmt->priv_data, "rtpflags", "h264_mode0"))mode = 0;if (p->extradata_size) {config = extradata2psets(fmt, p);}av_strlcatf(buff, size, "a=rtpmap:%d H264/90000\r\n""a=fmtp:%d packetization-mode=%d%s\r\n",payload_type,payload_type, mode, config ? config : "");break;}......case AV_CODEC_ID_TEXT:av_strlcatf(buff, size, "a=rtpmap:%d t140/1000\r\n", payload_type);break;case AV_CODEC_ID_ASS:av_strlcatf(buff, size, "a=rtpmap:%d ass/1000\r\n", payload_type);break;default:/* Nothing special to do here... */break;

截止目前,使用ffmpeg推送rtsp字幕流的源码修改已经完成。
但若想使用ffmpeg播放非t140字幕编码的字幕流, 还差最后一步。

3.使sdp中的subtitle可以正确被解析

假设有以下sdp信息:

v=0
o=- 0 0 IN IP4 127.0.0.1
s=No Name
c=IN IP4 192.168.1.180
t=0 0
a=tool:libavformat 56.40.101
m=video 0 RTP/AVP 96
a=rtpmap:96 H264/90000
a=fmtp:96 packetization-mode=1; sprop-parameter-sets=Z24AMqbMpgHgCJ+XARAAGXTwBMS0CPGDGaA=,aOl4/LA=;
profile-level-id=6E0032
a=control:streamid=0
m=audio 0 RTP/AVP 97
a=rtpmap:97 MPEG4-GENERIC/48000/2
a=fmtp:97 profile-level-id=1;mode=AAC-hbr;sizelength=13;indexlength=3;indexdeltalength=3;
config=119056E500
a=control:streamid=1
m=text 0 RTP/AVP 98
a=rtpmap:98 t140/1000
m=text 0 RTP/AVP 99
a=rtpmap:99 ass/1000

以上文本信息描述了两个subtitle流:一个文本流(t140), 一个ass字幕流(ass)。
ffmpeg在解析sdp时会创建两个AVStream, 该AVStream的codec_type为AVMEDIA_TYPE_SUBTITLE, codec_id会调用 ff_rtp_handler_find_by_name 方法进行寻找。

看下ff_rtp_handler_find_by_name的具体实现

    const RTPDynamicProtocolHandler *ff_rtp_handler_find_by_name(const char *name, enum AVMediaType codec_type){void *i = 0;const RTPDynamicProtocolHandler *handler;while (handler = ff_rtp_handler_iterate(&i)) {if (handler->enc_name &&!av_strcasecmp(name, handler->enc_name) &&codec_type == handler->codec_type)return handler;}return NULL;}

ff_rtp_handler_iterate实现:

    const RTPDynamicProtocolHandler *ff_rtp_handler_iterate(void **opaque){uintptr_t i = (uintptr_t)*opaque;const RTPDynamicProtocolHandler *r = rtp_dynamic_protocol_handler_list[i];if (r)*opaque = (void*)(i + 1);return r;}

即通过遍历rtpdec.c中的rtp_dynamic_protocol_handler_list去寻找符合要求的RTPDynamicProtocolHandler,所以我们需要在rtpdec.c中添加有关ass编码器的RTPDynamicProtocolHandler,同时将对应的地址加入到list中.

注意:
          或许因为rfc标准的原因,t140对应的动态协议已经被实现了, 所以若是推送的rtsp字幕流的编码器名称为t140,则无需修改ffmpeg源码也可以进行解析。

static RTPDynamicProtocolHandler t140_dynamic_handler = { /* RFC 4103 */.enc_name   = "t140",.codec_type = AVMEDIA_TYPE_SUBTITLE,.codec_id   = AV_CODEC_ID_TEXT,
};static RTPDynamicProtocolHandler ass_dynamic_handler = {.enc_name   = "ass",.codec_type = AVMEDIA_TYPE_SUBTITLE,.codec_id   = AV_CODEC_ID_ASS,
};static const RTPDynamicProtocolHandler *rtp_dynamic_protocol_handler_list[] = {/* rtp */&ff_ac3_dynamic_handler,......&t140_dynamic_handler,&ass_dynamic_handler,......
};

至此,修改完毕。

4.代码添加text字幕流

一段代码节选,添加一个字幕流到rtsp流中:

    bool RtspPusher::AddInfoStream(unsigned &streamIndex){if(!m_outputCtx) //AVFormatContextreturn false;AVStream * outStream = avformat_new_stream(m_outputCtx, NULL);AVCodec * encoder = avcodec_find_encoder(AV_CODEC_ID_TEXT);if(encoder == NULL)return false;AVCodecContext * encoderContext = avcodec_alloc_context3(encoder);int ret = avcodec_parameters_from_context(outStream->codecpar, encoderContext);avcodec_free_context(&encoderContext);if(ret < 0)return false;outStream->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE;streamIndex = m_outputCtx->nb_streams - 1;return true;}

欢迎转载: https://blog.csdn.net/shizheng163

使用ffmpeg添加rtsp字幕流 (t140)相关推荐

  1. FFmpeg 获取 rtsp rtmp 流

    使用 FFmpeg 获取 rtsp/rtmp 流非常方便,将开发 rtsp/rtmp 客户端工作变的简单了许多. 将 rtsp/rtmp 流路径送入 avformat_open_input 函数进行打 ...

  2. ffmpeg添加双语字幕

    [FFMPEG命令行操作]为视频添加双语字幕(附图)(不借助其他工具,只通过命令的组合实现) 核心思想:重复使用ffmpeg字幕添加命令,利用字幕的上下位置,划分中英文字幕显示位置 准备素材,如下图所 ...

  3. ffmpeg添加mpeg ps流的pcm的解码支持

    ffmpeg原本不支持mpeg ps流,原因有两个.首先在编码时,ffmpeg没有在流中写入psm头:其次,在解码时,只在读文件头的时候判断了流的类型,而ps流中,流类型是在psm头中的,这样ffmp ...

  4. 07-----给音视频文件添加字幕流

    添加字幕流可以使用ACHTIME软件去添加. 一 下载ACHTIME软件 在下载之前我们需要注册一个账号.然后才能下载. http://arctime.cn/download.html 二 添加字幕流 ...

  5. 20.RTSP取流实现方法

    文章目录 1. RTSP测试链接 2. RTSP 取流实现 2.1 QT+FFmpeg实现RTSP取流 2.2 QT+OpenCV实现RTSP取流 2.3 qt+vlc实现rtsp取流 1. RTSP ...

  6. FFMpeg 多路视频裸流截图保存为图片有马赛克以及图片不更新延迟的问题

    项目中多路RTSP流输入每路输入又有多路不同分辨率的输出 ,FFMpeg 通过RTSP拉流  经过海思转码之后 通过srs_librtmp  推送RTMP到服务器,动态增加输入输出等等 ,这部分的工作 ...

  7. RTSP再学习 -- 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/78214267 既然已经可以通过 RTSP 获取h264 裸流了.那么通过 F ...

  8. 音视频开发(17)---RTSP再学习 -- 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中

    RTSP再学习 -- 利用FFmpeg 将 rtsp 获取H264裸流并保存到文件中 https://blog.csdn.net/qq_29350001/article/details/7821426 ...

  9. FFMPEG之RTSP获取H264/H265裸流保存文件

    参考:https://blog.csdn.net/weixin_42432281/article/details/88348124 1 目标背景 本文的目的是实现linux嵌入式端ffmpeg读取网络 ...

最新文章

  1. 【Qt】Qt5.x移植后的环境配置(imx6)
  2. 奕新集团--RAC环境后续
  3. kafka高可用(集群)
  4. 青龙面板node-onebot 教程
  5. C#:如何去掉groupbox的边框线
  6. Java求字符串中出现次数最多的字符
  7. python中print怎么用_python的print怎么用
  8. 攻城狮危险:波士顿动力机器狗去福特当工程师了!
  9. 使用无锁的方式和有锁的方式的程序性能对比
  10. 解决maven项目Cannot change version of project facet Dynamic web module to 3.0
  11. java hashset retain_Java HashSet retainAll()用法及代码示例
  12. 昆明理工大学计算机考研分数线,昆明理工大学2015考研分数线已公布
  13. FortiClient VPN连接至98%时报错:Unable to establish the VPN connection.(E=98,T-981011001,M99,R10)
  14. 手机显示仅限紧急呼叫 无服务 以及无信号的解决教程
  15. 在家怎么做炸酱面 炸酱面做法
  16. vue(slot-卡槽)
  17. 第十二届蓝桥杯大赛模拟赛(第二期)
  18. Flink scal api 不支持RichAsyncFunction
  19. 后门之王:谈一谈加密算法中的数学后门
  20. Eclipse Mac OS 安装中文简体语言包

热门文章

  1. linux脚本剪切文件覆盖了怎么恢复,剪切的文件如何恢复 被剪切或删除的文件夹怎么恢复...
  2. 在linux系统下java实现pdf导出汉字无法显示_ubuntu/Linux PDF文件中文无法显示或中文为方块的解决方法...
  3. 电驴、金山卫士、flamingoIM、filezilla等几套开源源码送给大家
  4. 2022年监理工程师案例分析考试每日一练及答案
  5. python浙大版pta第七章
  6. IOS 动态获取键盘高度
  7. 物流APP开发要素(源码对接)
  8. SDOI2017 Round1 解题报告
  9. 智慧能耗在线监测系统
  10. 京东jos对接爬坑过程