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