2 * codec-specific routines used to interface between MPlayer
3 * and the "LIVE555 Streaming Media" libraries
5 * This file is part of MPlayer.
7 * MPlayer is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * MPlayer 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
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "demux_rtp_internal.h"
27 #include "libavutil/base64.h"
30 #ifdef CONFIG_LIBAVCODEC
31 AVCodecParserContext
* h264parserctx
;
32 AVCodecContext
*avcctx
;
36 static unsigned char* parseH264ConfigStr( char const* configStr
,
37 unsigned int& configSize
)
45 if( configStr
== NULL
|| *configStr
== '\0' )
47 psz
= dup
= strdup( configStr
);
49 /* Count the number of comma's */
50 for( psz
= dup
; *psz
!= '\0'; ++psz
)
59 unsigned char *cfg
= new unsigned char[5 * strlen(dup
)];
61 for( i
= 0; i
< i_records
; i
++ )
64 cfg
[configSize
++] = 0x00;
65 cfg
[configSize
++] = 0x00;
66 cfg
[configSize
++] = 0x01;
67 configSize
+= av_base64_decode( (uint8_t*)&cfg
[configSize
],
69 5 * strlen(dup
) - 3 );
73 if( dup
) free( dup
);
79 needVideoFrameRate(demuxer_t
* demuxer
, MediaSubsession
* subsession
); // forward
81 parseQTState_video(QuickTimeGenericRTPSource::QTState
const& qtState
,
82 unsigned& fourcc
); // forward
84 parseQTState_audio(QuickTimeGenericRTPSource::QTState
const& qtState
,
85 unsigned& fourcc
, unsigned& numChannels
); // forward
87 static BITMAPINFOHEADER
* insertVideoExtradata(BITMAPINFOHEADER
*bih
,
88 unsigned char * extraData
,
91 BITMAPINFOHEADER
* original
= bih
;
92 if (!size
|| size
> INT_MAX
- sizeof(BITMAPINFOHEADER
))
94 bih
= (BITMAPINFOHEADER
*)realloc(bih
, sizeof(BITMAPINFOHEADER
) + size
);
97 bih
->biSize
= sizeof(BITMAPINFOHEADER
) + size
;
98 memcpy(bih
+1, extraData
, size
);
102 void rtpCodecInitialize_video(demuxer_t
* demuxer
,
103 MediaSubsession
* subsession
,
106 // Create a dummy video stream header
107 // to make the main MPlayer code happy:
108 sh_video_t
* sh_video
= new_sh_video(demuxer
,0);
109 BITMAPINFOHEADER
* bih
110 = (BITMAPINFOHEADER
*)calloc(1,sizeof(BITMAPINFOHEADER
));
111 bih
->biSize
= sizeof(BITMAPINFOHEADER
);
113 demux_stream_t
* d_video
= demuxer
->video
;
114 d_video
->sh
= sh_video
; sh_video
->ds
= d_video
;
116 // Map known video MIME types to the BITMAPINFOHEADER parameters
117 // that this program uses. (Note that not all types need all
118 // of the parameters to be set.)
119 if (strcmp(subsession
->codecName(), "MPV") == 0) {
120 flags
|= RTPSTATE_IS_MPEG12_VIDEO
;
121 } else if (strcmp(subsession
->codecName(), "MP1S") == 0 ||
122 strcmp(subsession
->codecName(), "MP2T") == 0) {
123 flags
|= RTPSTATE_IS_MPEG12_VIDEO
|RTPSTATE_IS_MULTIPLEXED
;
124 } else if (strcmp(subsession
->codecName(), "H263") == 0 ||
125 strcmp(subsession
->codecName(), "H263-2000") == 0 ||
126 strcmp(subsession
->codecName(), "H263-1998") == 0) {
127 bih
->biCompression
= sh_video
->format
128 = mmioFOURCC('H','2','6','3');
129 needVideoFrameRate(demuxer
, subsession
);
130 } else if (strcmp(subsession
->codecName(), "H264") == 0) {
131 bih
->biCompression
= sh_video
->format
132 = mmioFOURCC('H','2','6','4');
133 unsigned int configLen
= 0;
134 unsigned char* configData
135 = parseH264ConfigStr(subsession
->fmtp_spropparametersets(), configLen
);
136 sh_video
->bih
= bih
= insertVideoExtradata(bih
, configData
, configLen
);
138 #ifdef CONFIG_LIBAVCODEC
139 avcodec_register_all();
140 h264parserctx
= av_parser_init(CODEC_ID_H264
);
141 avcctx
= avcodec_alloc_context();
143 needVideoFrameRate(demuxer
, subsession
);
144 } else if (strcmp(subsession
->codecName(), "H261") == 0) {
145 bih
->biCompression
= sh_video
->format
146 = mmioFOURCC('H','2','6','1');
147 needVideoFrameRate(demuxer
, subsession
);
148 } else if (strcmp(subsession
->codecName(), "JPEG") == 0) {
149 bih
->biCompression
= sh_video
->format
150 = mmioFOURCC('M','J','P','G');
151 needVideoFrameRate(demuxer
, subsession
);
152 } else if (strcmp(subsession
->codecName(), "MP4V-ES") == 0) {
153 bih
->biCompression
= sh_video
->format
154 = mmioFOURCC('m','p','4','v');
155 // For the codec to work correctly, it may need a 'VOL Header' to be
156 // inserted at the front of the data stream. Construct this from the
157 // "config" MIME parameter, which was present (hopefully) in the
158 // session's SDP description:
160 unsigned char* configData
161 = parseGeneralConfigStr(subsession
->fmtp_config(), configLen
);
162 sh_video
->bih
= bih
= insertVideoExtradata(bih
, configData
, configLen
);
163 needVideoFrameRate(demuxer
, subsession
);
164 } else if (strcmp(subsession
->codecName(), "X-QT") == 0 ||
165 strcmp(subsession
->codecName(), "X-QUICKTIME") == 0) {
166 // QuickTime generic RTP format, as described in
167 // http://developer.apple.com/quicktime/icefloe/dispatch026.html
169 // We can't initialize this stream until we've received the first packet
170 // that has QuickTime "sdAtom" information in the header. So, keep
171 // reading packets until we get one:
172 unsigned char* packetData
; unsigned packetDataLen
; float pts
;
173 QuickTimeGenericRTPSource
* qtRTPSource
174 = (QuickTimeGenericRTPSource
*)(subsession
->rtpSource());
177 if (!awaitRTPPacket(demuxer
, demuxer
->video
,
178 packetData
, packetDataLen
, pts
)) {
181 } while (!parseQTState_video(qtRTPSource
->qtState
, fourcc
));
183 bih
->biCompression
= sh_video
->format
= fourcc
;
184 bih
->biWidth
= qtRTPSource
->qtState
.width
;
185 bih
->biHeight
= qtRTPSource
->qtState
.height
;
186 if (qtRTPSource
->qtState
.sdAtomSize
> 83)
187 bih
->biBitCount
= qtRTPSource
->qtState
.sdAtom
[83];
188 uint8_t *pos
= (uint8_t*)qtRTPSource
->qtState
.sdAtom
+ 86;
189 uint8_t *endpos
= (uint8_t*)qtRTPSource
->qtState
.sdAtom
190 + qtRTPSource
->qtState
.sdAtomSize
;
191 while (pos
+8 < endpos
) {
192 unsigned atomLength
= pos
[0]<<24 | pos
[1]<<16 | pos
[2]<<8 | pos
[3];
193 if (atomLength
== 0 || atomLength
> endpos
-pos
) break;
194 if ((!memcmp(pos
+4, "avcC", 4) && fourcc
==mmioFOURCC('a','v','c','1') ||
195 !memcmp(pos
+4, "esds", 4) ||
196 !memcmp(pos
+4, "SMI ", 4) && fourcc
==mmioFOURCC('S','V','Q','3')) &&
198 sh_video
->bih
= bih
=
199 insertVideoExtradata(bih
, pos
+8, atomLength
-8);
204 needVideoFrameRate(demuxer
, subsession
);
207 "Unknown MPlayer format code for MIME type \"video/%s\"\n",
208 subsession
->codecName());
212 void rtpCodecInitialize_audio(demuxer_t
* demuxer
,
213 MediaSubsession
* subsession
,
216 // Create a dummy audio stream header
217 // to make the main MPlayer code happy:
218 sh_audio_t
* sh_audio
= new_sh_audio(demuxer
,0);
219 WAVEFORMATEX
* wf
= (WAVEFORMATEX
*)calloc(1,sizeof(WAVEFORMATEX
));
221 demux_stream_t
* d_audio
= demuxer
->audio
;
222 d_audio
->sh
= sh_audio
; sh_audio
->ds
= d_audio
;
223 d_audio
->id
= sh_audio
->aid
;
225 wf
->nChannels
= subsession
->numChannels();
227 // Map known audio MIME types to the WAVEFORMATEX parameters
228 // that this program uses. (Note that not all types need all
229 // of the parameters to be set.)
231 = subsession
->rtpSource()->timestampFrequency(); // by default
232 if (strcmp(subsession
->codecName(), "MPA") == 0 ||
233 strcmp(subsession
->codecName(), "MPA-ROBUST") == 0 ||
234 strcmp(subsession
->codecName(), "X-MP3-DRAFT-00") == 0) {
235 wf
->wFormatTag
= sh_audio
->format
= 0x55;
236 // Note: 0x55 is for layer III, but should work for I,II also
237 wf
->nSamplesPerSec
= 0; // sample rate is deduced from the data
238 } else if (strcmp(subsession
->codecName(), "AC3") == 0) {
239 wf
->wFormatTag
= sh_audio
->format
= 0x2000;
240 wf
->nSamplesPerSec
= 0; // sample rate is deduced from the data
241 } else if (strcmp(subsession
->codecName(), "L16") == 0) {
242 wf
->wFormatTag
= sh_audio
->format
= 0x736f7774; // "twos"
244 wf
->wBitsPerSample
= 16;
246 } else if (strcmp(subsession
->codecName(), "L8") == 0) {
247 wf
->wFormatTag
= sh_audio
->format
= 0x20776172; // "raw "
249 wf
->wBitsPerSample
= 8;
251 } else if (strcmp(subsession
->codecName(), "PCMU") == 0) {
252 wf
->wFormatTag
= sh_audio
->format
= 0x7;
253 wf
->nAvgBytesPerSec
= 8000;
255 wf
->wBitsPerSample
= 8;
257 } else if (strcmp(subsession
->codecName(), "PCMA") == 0) {
258 wf
->wFormatTag
= sh_audio
->format
= 0x6;
259 wf
->nAvgBytesPerSec
= 8000;
261 wf
->wBitsPerSample
= 8;
263 } else if (strcmp(subsession
->codecName(), "AMR") == 0) {
264 wf
->wFormatTag
= sh_audio
->format
= mmioFOURCC('s','a','m','r');
265 } else if (strcmp(subsession
->codecName(), "AMR-WB") == 0) {
266 wf
->wFormatTag
= sh_audio
->format
= mmioFOURCC('s','a','w','b');
267 } else if (strcmp(subsession
->codecName(), "GSM") == 0) {
268 wf
->wFormatTag
= sh_audio
->format
= mmioFOURCC('a','g','s','m');
269 wf
->nAvgBytesPerSec
= 1650;
270 wf
->nBlockAlign
= 33;
271 wf
->wBitsPerSample
= 16;
273 } else if (strcmp(subsession
->codecName(), "QCELP") == 0) {
274 wf
->wFormatTag
= sh_audio
->format
= mmioFOURCC('Q','c','l','p');
275 wf
->nAvgBytesPerSec
= 1750;
276 wf
->nBlockAlign
= 35;
277 wf
->wBitsPerSample
= 16;
279 } else if (strcmp(subsession
->codecName(), "MP4A-LATM") == 0) {
280 wf
->wFormatTag
= sh_audio
->format
= mmioFOURCC('m','p','4','a');
281 // For the codec to work correctly, it needs "AudioSpecificConfig"
282 // data, which is parsed from the "StreamMuxConfig" string that
283 // was present (hopefully) in the SDP description:
284 unsigned codecdata_len
;
286 = parseStreamMuxConfigStr(subsession
->fmtp_config(),
288 sh_audio
->codecdata_len
= codecdata_len
;
289 //faad doesn't understand LATM's data length field, so omit it
290 ((MPEG4LATMAudioRTPSource
*)subsession
->rtpSource())->omitLATMDataLengthField();
291 } else if (strcmp(subsession
->codecName(), "MPEG4-GENERIC") == 0) {
292 wf
->wFormatTag
= sh_audio
->format
= mmioFOURCC('m','p','4','a');
293 // For the codec to work correctly, it needs "AudioSpecificConfig"
294 // data, which was present (hopefully) in the SDP description:
295 unsigned codecdata_len
;
297 = parseGeneralConfigStr(subsession
->fmtp_config(),
299 sh_audio
->codecdata_len
= codecdata_len
;
300 } else if (strcmp(subsession
->codecName(), "X-QT") == 0 ||
301 strcmp(subsession
->codecName(), "X-QUICKTIME") == 0) {
302 // QuickTime generic RTP format, as described in
303 // http://developer.apple.com/quicktime/icefloe/dispatch026.html
305 // We can't initialize this stream until we've received the first packet
306 // that has QuickTime "sdAtom" information in the header. So, keep
307 // reading packets until we get one:
308 unsigned char* packetData
; unsigned packetDataLen
; float pts
;
309 QuickTimeGenericRTPSource
* qtRTPSource
310 = (QuickTimeGenericRTPSource
*)(subsession
->rtpSource());
311 unsigned fourcc
, numChannels
;
313 if (!awaitRTPPacket(demuxer
, demuxer
->audio
,
314 packetData
, packetDataLen
, pts
)) {
317 } while (!parseQTState_audio(qtRTPSource
->qtState
, fourcc
, numChannels
));
319 wf
->wFormatTag
= sh_audio
->format
= fourcc
;
320 wf
->nChannels
= numChannels
;
322 if (qtRTPSource
->qtState
.sdAtomSize
> 33) {
323 wf
->wBitsPerSample
= qtRTPSource
->qtState
.sdAtom
[27];
324 wf
->nSamplesPerSec
= qtRTPSource
->qtState
.sdAtom
[32]<<8|qtRTPSource
->qtState
.sdAtom
[33];
326 uint8_t *pos
= (uint8_t*)qtRTPSource
->qtState
.sdAtom
+ 52;
327 uint8_t *endpos
= (uint8_t*)qtRTPSource
->qtState
.sdAtom
328 + qtRTPSource
->qtState
.sdAtomSize
;
329 while (pos
+8 < endpos
) {
330 unsigned atomLength
= pos
[0]<<24 | pos
[1]<<16 | pos
[2]<<8 | pos
[3];
331 if (atomLength
== 0 || atomLength
> endpos
-pos
) break;
332 if (!memcmp(pos
+4, "wave", 4) && fourcc
==mmioFOURCC('Q','D','M','2') &&
334 atomLength
<= INT_MAX
) {
335 sh_audio
->codecdata
= (unsigned char*) malloc(atomLength
-8);
336 if (sh_audio
->codecdata
) {
337 memcpy(sh_audio
->codecdata
, pos
+8, atomLength
-8);
338 sh_audio
->codecdata_len
= atomLength
-8;
346 "Unknown MPlayer format code for MIME type \"audio/%s\"\n",
347 subsession
->codecName());
351 static void needVideoFrameRate(demuxer_t
* demuxer
,
352 MediaSubsession
* subsession
) {
353 // For some codecs, MPlayer's decoding software can't (or refuses to :-)
354 // figure out the frame rate by itself, so (unless the user specifies
355 // it manually, using "-fps") we figure it out ourselves here, using the
356 // presentation timestamps in successive packets,
357 extern double force_fps
; if (force_fps
!= 0.0) return; // user used "-fps"
359 demux_stream_t
* d_video
= demuxer
->video
;
360 sh_video_t
* sh_video
= (sh_video_t
*)(d_video
->sh
);
362 // If we already know the subsession's video frame rate, use it:
363 int fps
= (int)(subsession
->videoFPS());
366 sh_video
->frametime
= 1.0f
/fps
;
370 // Keep looking at incoming frames until we see two with different,
371 // non-zero "pts" timestamps:
372 unsigned char* packetData
; unsigned packetDataLen
;
373 float lastPTS
= 0.0, curPTS
;
374 unsigned const maxNumFramesToWaitFor
= 300;
376 for (unsigned i
= 0; i
< maxNumFramesToWaitFor
; ++i
) {
377 if (!awaitRTPPacket(demuxer
, d_video
, packetData
, packetDataLen
, curPTS
)) {
381 if (curPTS
!= lastPTS
&& lastPTS
!= 0.0) {
382 // Use the difference between these two "pts"s to guess the frame rate.
383 // (should really check that there were no missing frames inbetween)#####
384 // Guess the frame rate as an integer. If it's not, use "-fps" instead.
385 fps
= (int)(1/fabs(curPTS
-lastPTS
) + 0.5); // rounding
386 if (fps
== lastfps
) {
387 fprintf(stderr
, "demux_rtp: Guessed the video frame rate as %d frames-per-second.\n\t(If this is wrong, use the \"-fps <frame-rate>\" option instead.)\n", fps
);
389 sh_video
->frametime
=1.0f
/fps
;
392 if (fps
>lastfps
) lastfps
= fps
;
396 fprintf(stderr
, "demux_rtp: Failed to guess the video frame rate\n");
400 parseQTState_video(QuickTimeGenericRTPSource::QTState
const& qtState
,
402 // qtState's "sdAtom" field is supposed to contain a QuickTime video
403 // 'sample description' atom. This atom's name is the 'fourcc' that we want:
404 char const* sdAtom
= qtState
.sdAtom
;
405 if (sdAtom
== NULL
|| qtState
.sdAtomSize
< 2*4) return False
;
407 fourcc
= *(unsigned*)(&sdAtom
[4]); // put in host order
412 parseQTState_audio(QuickTimeGenericRTPSource::QTState
const& qtState
,
413 unsigned& fourcc
, unsigned& numChannels
) {
414 // qtState's "sdAtom" field is supposed to contain a QuickTime audio
415 // 'sample description' atom. This atom's name is the 'fourcc' that we want.
416 // Also, the top half of the 5th word following the atom name should
417 // contain the number of channels ("numChannels") that we want:
418 char const* sdAtom
= qtState
.sdAtom
;
419 if (sdAtom
== NULL
|| qtState
.sdAtomSize
< 7*4) return False
;
421 fourcc
= *(unsigned*)(&sdAtom
[4]); // put in host order
423 char const* word7Ptr
= &sdAtom
[6*4];
424 numChannels
= (word7Ptr
[0]<<8)|(word7Ptr
[1]);