1cabdff1aSopenharmony_ci/* 2cabdff1aSopenharmony_ci * RTP/mpegts muxer 3cabdff1aSopenharmony_ci * Copyright (c) 2011 Martin Storsjo 4cabdff1aSopenharmony_ci * 5cabdff1aSopenharmony_ci * This file is part of FFmpeg. 6cabdff1aSopenharmony_ci * 7cabdff1aSopenharmony_ci * FFmpeg is free software; you can redistribute it and/or 8cabdff1aSopenharmony_ci * modify it under the terms of the GNU Lesser General Public 9cabdff1aSopenharmony_ci * License as published by the Free Software Foundation; either 10cabdff1aSopenharmony_ci * version 2.1 of the License, or (at your option) any later version. 11cabdff1aSopenharmony_ci * 12cabdff1aSopenharmony_ci * FFmpeg is distributed in the hope that it will be useful, 13cabdff1aSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 14cabdff1aSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15cabdff1aSopenharmony_ci * Lesser General Public License for more details. 16cabdff1aSopenharmony_ci * 17cabdff1aSopenharmony_ci * You should have received a copy of the GNU Lesser General Public 18cabdff1aSopenharmony_ci * License along with FFmpeg; if not, write to the Free Software 19cabdff1aSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20cabdff1aSopenharmony_ci */ 21cabdff1aSopenharmony_ci 22cabdff1aSopenharmony_ci#include "libavutil/mathematics.h" 23cabdff1aSopenharmony_ci#include "libavutil/opt.h" 24cabdff1aSopenharmony_ci#include "avformat.h" 25cabdff1aSopenharmony_ci#include "avio_internal.h" 26cabdff1aSopenharmony_ci 27cabdff1aSopenharmony_citypedef struct MuxChain { 28cabdff1aSopenharmony_ci const AVClass *class; 29cabdff1aSopenharmony_ci AVFormatContext *mpegts_ctx; 30cabdff1aSopenharmony_ci AVFormatContext *rtp_ctx; 31cabdff1aSopenharmony_ci AVPacket *pkt; 32cabdff1aSopenharmony_ci AVDictionary* mpegts_muxer_options; 33cabdff1aSopenharmony_ci AVDictionary* rtp_muxer_options; 34cabdff1aSopenharmony_ci} MuxChain; 35cabdff1aSopenharmony_ci 36cabdff1aSopenharmony_cistatic int rtp_mpegts_write_close(AVFormatContext *s) 37cabdff1aSopenharmony_ci{ 38cabdff1aSopenharmony_ci MuxChain *chain = s->priv_data; 39cabdff1aSopenharmony_ci 40cabdff1aSopenharmony_ci if (chain->mpegts_ctx) { 41cabdff1aSopenharmony_ci av_write_trailer(chain->mpegts_ctx); 42cabdff1aSopenharmony_ci ffio_free_dyn_buf(&chain->mpegts_ctx->pb); 43cabdff1aSopenharmony_ci avformat_free_context(chain->mpegts_ctx); 44cabdff1aSopenharmony_ci } 45cabdff1aSopenharmony_ci if (chain->rtp_ctx) { 46cabdff1aSopenharmony_ci av_write_trailer(chain->rtp_ctx); 47cabdff1aSopenharmony_ci avformat_free_context(chain->rtp_ctx); 48cabdff1aSopenharmony_ci } 49cabdff1aSopenharmony_ci 50cabdff1aSopenharmony_ci av_packet_free(&chain->pkt); 51cabdff1aSopenharmony_ci 52cabdff1aSopenharmony_ci return 0; 53cabdff1aSopenharmony_ci} 54cabdff1aSopenharmony_ci 55cabdff1aSopenharmony_cistatic int rtp_mpegts_write_header(AVFormatContext *s) 56cabdff1aSopenharmony_ci{ 57cabdff1aSopenharmony_ci MuxChain *chain = s->priv_data; 58cabdff1aSopenharmony_ci AVFormatContext *mpegts_ctx = NULL, *rtp_ctx = NULL; 59cabdff1aSopenharmony_ci const AVOutputFormat *mpegts_format = av_guess_format("mpegts", NULL, NULL); 60cabdff1aSopenharmony_ci const AVOutputFormat *rtp_format = av_guess_format("rtp", NULL, NULL); 61cabdff1aSopenharmony_ci int i, ret = AVERROR(ENOMEM); 62cabdff1aSopenharmony_ci AVStream *st; 63cabdff1aSopenharmony_ci AVDictionary *mpegts_muxer_options = NULL; 64cabdff1aSopenharmony_ci AVDictionary *rtp_muxer_options = NULL; 65cabdff1aSopenharmony_ci 66cabdff1aSopenharmony_ci if (!mpegts_format || !rtp_format) 67cabdff1aSopenharmony_ci return AVERROR(ENOSYS); 68cabdff1aSopenharmony_ci mpegts_ctx = avformat_alloc_context(); 69cabdff1aSopenharmony_ci if (!mpegts_ctx) 70cabdff1aSopenharmony_ci return AVERROR(ENOMEM); 71cabdff1aSopenharmony_ci chain->pkt = av_packet_alloc(); 72cabdff1aSopenharmony_ci if (!chain->pkt) 73cabdff1aSopenharmony_ci goto fail; 74cabdff1aSopenharmony_ci mpegts_ctx->oformat = mpegts_format; 75cabdff1aSopenharmony_ci mpegts_ctx->max_delay = s->max_delay; 76cabdff1aSopenharmony_ci av_dict_copy(&mpegts_ctx->metadata, s->metadata, 0); 77cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) { 78cabdff1aSopenharmony_ci AVStream* st = avformat_new_stream(mpegts_ctx, NULL); 79cabdff1aSopenharmony_ci if (!st) 80cabdff1aSopenharmony_ci goto fail; 81cabdff1aSopenharmony_ci st->time_base = s->streams[i]->time_base; 82cabdff1aSopenharmony_ci st->sample_aspect_ratio = s->streams[i]->sample_aspect_ratio; 83cabdff1aSopenharmony_ci st->id = s->streams[i]->id; 84cabdff1aSopenharmony_ci avcodec_parameters_copy(st->codecpar, s->streams[i]->codecpar); 85cabdff1aSopenharmony_ci } 86cabdff1aSopenharmony_ci if ((ret = avio_open_dyn_buf(&mpegts_ctx->pb)) < 0) 87cabdff1aSopenharmony_ci goto fail; 88cabdff1aSopenharmony_ci 89cabdff1aSopenharmony_ci av_dict_copy(&mpegts_muxer_options, chain->mpegts_muxer_options, 0); 90cabdff1aSopenharmony_ci 91cabdff1aSopenharmony_ci ret = avformat_write_header(mpegts_ctx, &mpegts_muxer_options); 92cabdff1aSopenharmony_ci av_dict_free(&mpegts_muxer_options); 93cabdff1aSopenharmony_ci if (ret < 0) 94cabdff1aSopenharmony_ci goto fail; 95cabdff1aSopenharmony_ci 96cabdff1aSopenharmony_ci for (i = 0; i < s->nb_streams; i++) 97cabdff1aSopenharmony_ci s->streams[i]->time_base = mpegts_ctx->streams[i]->time_base; 98cabdff1aSopenharmony_ci 99cabdff1aSopenharmony_ci chain->mpegts_ctx = mpegts_ctx; 100cabdff1aSopenharmony_ci mpegts_ctx = NULL; 101cabdff1aSopenharmony_ci 102cabdff1aSopenharmony_ci rtp_ctx = avformat_alloc_context(); 103cabdff1aSopenharmony_ci if (!rtp_ctx) { 104cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 105cabdff1aSopenharmony_ci goto fail; 106cabdff1aSopenharmony_ci } 107cabdff1aSopenharmony_ci rtp_ctx->oformat = rtp_format; 108cabdff1aSopenharmony_ci st = avformat_new_stream(rtp_ctx, NULL); 109cabdff1aSopenharmony_ci if (!st) { 110cabdff1aSopenharmony_ci ret = AVERROR(ENOMEM); 111cabdff1aSopenharmony_ci goto fail; 112cabdff1aSopenharmony_ci } 113cabdff1aSopenharmony_ci st->time_base.num = 1; 114cabdff1aSopenharmony_ci st->time_base.den = 90000; 115cabdff1aSopenharmony_ci st->codecpar->codec_id = AV_CODEC_ID_MPEG2TS; 116cabdff1aSopenharmony_ci rtp_ctx->pb = s->pb; 117cabdff1aSopenharmony_ci av_dict_copy(&rtp_muxer_options, chain->rtp_muxer_options, 0); 118cabdff1aSopenharmony_ci ret = avformat_write_header(rtp_ctx, &rtp_muxer_options); 119cabdff1aSopenharmony_ci av_dict_free(&rtp_muxer_options); 120cabdff1aSopenharmony_ci if (ret < 0) 121cabdff1aSopenharmony_ci goto fail; 122cabdff1aSopenharmony_ci 123cabdff1aSopenharmony_ci chain->rtp_ctx = rtp_ctx; 124cabdff1aSopenharmony_ci 125cabdff1aSopenharmony_ci return 0; 126cabdff1aSopenharmony_ci 127cabdff1aSopenharmony_cifail: 128cabdff1aSopenharmony_ci if (mpegts_ctx) { 129cabdff1aSopenharmony_ci ffio_free_dyn_buf(&mpegts_ctx->pb); 130cabdff1aSopenharmony_ci av_dict_free(&mpegts_ctx->metadata); 131cabdff1aSopenharmony_ci avformat_free_context(mpegts_ctx); 132cabdff1aSopenharmony_ci } 133cabdff1aSopenharmony_ci avformat_free_context(rtp_ctx); 134cabdff1aSopenharmony_ci rtp_mpegts_write_close(s); 135cabdff1aSopenharmony_ci return ret; 136cabdff1aSopenharmony_ci} 137cabdff1aSopenharmony_ci 138cabdff1aSopenharmony_cistatic int rtp_mpegts_write_packet(AVFormatContext *s, AVPacket *pkt) 139cabdff1aSopenharmony_ci{ 140cabdff1aSopenharmony_ci MuxChain *chain = s->priv_data; 141cabdff1aSopenharmony_ci int ret = 0, size; 142cabdff1aSopenharmony_ci uint8_t *buf; 143cabdff1aSopenharmony_ci AVPacket *local_pkt = chain->pkt; 144cabdff1aSopenharmony_ci 145cabdff1aSopenharmony_ci if (!chain->mpegts_ctx->pb) { 146cabdff1aSopenharmony_ci if ((ret = avio_open_dyn_buf(&chain->mpegts_ctx->pb)) < 0) 147cabdff1aSopenharmony_ci return ret; 148cabdff1aSopenharmony_ci } 149cabdff1aSopenharmony_ci if ((ret = av_write_frame(chain->mpegts_ctx, pkt)) < 0) 150cabdff1aSopenharmony_ci return ret; 151cabdff1aSopenharmony_ci size = avio_close_dyn_buf(chain->mpegts_ctx->pb, &buf); 152cabdff1aSopenharmony_ci chain->mpegts_ctx->pb = NULL; 153cabdff1aSopenharmony_ci if (size == 0) { 154cabdff1aSopenharmony_ci av_free(buf); 155cabdff1aSopenharmony_ci return 0; 156cabdff1aSopenharmony_ci } 157cabdff1aSopenharmony_ci av_packet_unref(local_pkt); 158cabdff1aSopenharmony_ci local_pkt->data = buf; 159cabdff1aSopenharmony_ci local_pkt->size = size; 160cabdff1aSopenharmony_ci local_pkt->stream_index = 0; 161cabdff1aSopenharmony_ci if (pkt->pts != AV_NOPTS_VALUE) 162cabdff1aSopenharmony_ci local_pkt->pts = av_rescale_q(pkt->pts, 163cabdff1aSopenharmony_ci s->streams[pkt->stream_index]->time_base, 164cabdff1aSopenharmony_ci chain->rtp_ctx->streams[0]->time_base); 165cabdff1aSopenharmony_ci if (pkt->dts != AV_NOPTS_VALUE) 166cabdff1aSopenharmony_ci local_pkt->dts = av_rescale_q(pkt->dts, 167cabdff1aSopenharmony_ci s->streams[pkt->stream_index]->time_base, 168cabdff1aSopenharmony_ci chain->rtp_ctx->streams[0]->time_base); 169cabdff1aSopenharmony_ci ret = av_write_frame(chain->rtp_ctx, local_pkt); 170cabdff1aSopenharmony_ci av_free(buf); 171cabdff1aSopenharmony_ci 172cabdff1aSopenharmony_ci return ret; 173cabdff1aSopenharmony_ci} 174cabdff1aSopenharmony_ci 175cabdff1aSopenharmony_ci#define OFFSET(x) offsetof(MuxChain, x) 176cabdff1aSopenharmony_ci#define E AV_OPT_FLAG_ENCODING_PARAM 177cabdff1aSopenharmony_cistatic const AVOption options[] = { 178cabdff1aSopenharmony_ci { "mpegts_muxer_options", "set list of options for the MPEG-TS muxer", OFFSET(mpegts_muxer_options), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E }, 179cabdff1aSopenharmony_ci { "rtp_muxer_options", "set list of options for the RTP muxer", OFFSET(rtp_muxer_options), AV_OPT_TYPE_DICT, {.str = NULL}, 0, 0, E }, 180cabdff1aSopenharmony_ci { NULL }, 181cabdff1aSopenharmony_ci}; 182cabdff1aSopenharmony_ci 183cabdff1aSopenharmony_cistatic const AVClass rtp_mpegts_class = { 184cabdff1aSopenharmony_ci .class_name = "rtp_mpegts muxer", 185cabdff1aSopenharmony_ci .item_name = av_default_item_name, 186cabdff1aSopenharmony_ci .option = options, 187cabdff1aSopenharmony_ci .version = LIBAVUTIL_VERSION_INT, 188cabdff1aSopenharmony_ci}; 189cabdff1aSopenharmony_ci 190cabdff1aSopenharmony_ciconst AVOutputFormat ff_rtp_mpegts_muxer = { 191cabdff1aSopenharmony_ci .name = "rtp_mpegts", 192cabdff1aSopenharmony_ci .long_name = NULL_IF_CONFIG_SMALL("RTP/mpegts output format"), 193cabdff1aSopenharmony_ci .priv_data_size = sizeof(MuxChain), 194cabdff1aSopenharmony_ci .audio_codec = AV_CODEC_ID_AAC, 195cabdff1aSopenharmony_ci .video_codec = AV_CODEC_ID_MPEG4, 196cabdff1aSopenharmony_ci .write_header = rtp_mpegts_write_header, 197cabdff1aSopenharmony_ci .write_packet = rtp_mpegts_write_packet, 198cabdff1aSopenharmony_ci .write_trailer = rtp_mpegts_write_close, 199cabdff1aSopenharmony_ci .priv_class = &rtp_mpegts_class, 200cabdff1aSopenharmony_ci}; 201