Mercurial > mplayer.hg
annotate libmpdemux/demux_rtp_codec.cpp @ 32676:db882cd69776
Do not #define _WIN32 on the command line for Cygwin.
Newer Cygwin versions no longer do this and hopefully we should be able
to survive without this hack as well. This change necessitates adapting
two #ifdefs in the MPlayer codebase. It is committed untested as I do
not have access to a Cygwin system.
author | diego |
---|---|
date | Thu, 06 Jan 2011 12:42:59 +0000 |
parents | 8fa2f43cb760 |
children | a5d8b198c214 |
rev | line source |
---|---|
29238
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
1 /* |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
2 * codec-specific routines used to interface between MPlayer |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
3 * and the "LIVE555 Streaming Media" libraries |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
4 * |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
5 * This file is part of MPlayer. |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
6 * |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
7 * MPlayer is free software; you can redistribute it and/or modify |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
8 * it under the terms of the GNU General Public License as published by |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
9 * the Free Software Foundation; either version 2 of the License, or |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
10 * (at your option) any later version. |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
11 * |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
12 * MPlayer is distributed in the hope that it will be useful, |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
15 * GNU General Public License for more details. |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
16 * |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
17 * You should have received a copy of the GNU General Public License along |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
18 * with MPlayer; if not, write to the Free Software Foundation, Inc., |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
d643e4643313
Add standard license header to all files in libmpdemux.
diego
parents:
27417
diff
changeset
|
20 */ |
9250 | 21 |
22 #include "demux_rtp_internal.h" | |
23 extern "C" { | |
21911
e86bb13ec44b
demux_rtp_codec.cpp:100: `INT_MAX' undeclared (first use this function)
diego
parents:
21871
diff
changeset
|
24 #include <limits.h> |
21983
a6b624360aef
better autodetection of framerate in case of h264; it works correctly with b-frames.
nicodvb
parents:
21911
diff
changeset
|
25 #include <math.h> |
9250 | 26 #include "stheader.h" |
26486 | 27 #include "libavutil/base64.h" |
22852 | 28 } |
29 | |
32142
4614728cab25
build system: Merge all FFmpeg library checks into a single FFmpeg check.
diego
parents:
31627
diff
changeset
|
30 #ifdef CONFIG_FFMPEG |
22852 | 31 AVCodecParserContext * h264parserctx; |
29453 | 32 AVCodecContext *avcctx; |
22852 | 33 #endif |
34 | |
35 // Copied from vlc | |
36 static unsigned char* parseH264ConfigStr( char const* configStr, | |
37 unsigned int& configSize ) | |
38 { | |
39 | |
40 char *dup, *psz; | |
41 int i, i_records = 1; | |
42 | |
43 if( configSize ) | |
44 configSize = 0; | |
45 if( configStr == NULL || *configStr == '\0' ) | |
46 return NULL; | |
47 psz = dup = strdup( configStr ); | |
48 | |
49 /* Count the number of comma's */ | |
50 for( psz = dup; *psz != '\0'; ++psz ) | |
51 { | |
52 if( *psz == ',') | |
53 { | |
54 ++i_records; | |
55 *psz = '\0'; | |
56 } | |
57 } | |
58 | |
59 unsigned char *cfg = new unsigned char[5 * strlen(dup)]; | |
60 psz = dup; | |
61 for( i = 0; i < i_records; i++ ) | |
62 { | |
63 | |
64 cfg[configSize++] = 0x00; | |
65 cfg[configSize++] = 0x00; | |
66 cfg[configSize++] = 0x01; | |
67 configSize += av_base64_decode( (uint8_t*)&cfg[configSize], | |
68 psz, | |
69 5 * strlen(dup) - 3 ); | |
70 | |
71 psz += strlen(psz)+1; | |
72 } | |
32537
8fa2f43cb760
Remove most of the NULL pointer check before free all over the code
cboesch
parents:
32142
diff
changeset
|
73 free( dup ); |
22852 | 74 |
75 return cfg; | |
9250 | 76 } |
77 | |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
78 static void |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
79 needVideoFrameRate(demuxer_t* demuxer, MediaSubsession* subsession); // forward |
9250 | 80 static Boolean |
81 parseQTState_video(QuickTimeGenericRTPSource::QTState const& qtState, | |
82 unsigned& fourcc); // forward | |
83 static Boolean | |
84 parseQTState_audio(QuickTimeGenericRTPSource::QTState const& qtState, | |
85 unsigned& fourcc, unsigned& numChannels); // forward | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29238
diff
changeset
|
86 |
22278
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
87 static BITMAPINFOHEADER * insertVideoExtradata(BITMAPINFOHEADER *bih, |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
88 unsigned char * extraData, |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
89 unsigned size) |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
90 { |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
91 BITMAPINFOHEADER * original = bih; |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
92 if (!size || size > INT_MAX - sizeof(BITMAPINFOHEADER)) |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
93 return bih; |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
94 bih = (BITMAPINFOHEADER*)realloc(bih, sizeof(BITMAPINFOHEADER) + size); |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
95 if (!bih) |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
96 return original; |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
97 bih->biSize = sizeof(BITMAPINFOHEADER) + size; |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
98 memcpy(bih+1, extraData, size); |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
99 return bih; |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
100 } |
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
101 |
9250 | 102 void rtpCodecInitialize_video(demuxer_t* demuxer, |
103 MediaSubsession* subsession, | |
104 unsigned& flags) { | |
105 flags = 0; | |
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); | |
112 sh_video->bih = bih; | |
113 demux_stream_t* d_video = demuxer->video; | |
114 d_video->sh = sh_video; sh_video->ds = d_video; | |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29238
diff
changeset
|
115 |
9250 | 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.) | |
10478
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
119 if (strcmp(subsession->codecName(), "MPV") == 0) { |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
120 flags |= RTPSTATE_IS_MPEG12_VIDEO; |
10478
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
121 } else if (strcmp(subsession->codecName(), "MP1S") == 0 || |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
122 strcmp(subsession->codecName(), "MP2T") == 0) { |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
123 flags |= RTPSTATE_IS_MPEG12_VIDEO|RTPSTATE_IS_MULTIPLEXED; |
9250 | 124 } else if (strcmp(subsession->codecName(), "H263") == 0 || |
22211 | 125 strcmp(subsession->codecName(), "H263-2000") == 0 || |
9250 | 126 strcmp(subsession->codecName(), "H263-1998") == 0) { |
127 bih->biCompression = sh_video->format | |
128 = mmioFOURCC('H','2','6','3'); | |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
129 needVideoFrameRate(demuxer, subsession); |
19415 | 130 } else if (strcmp(subsession->codecName(), "H264") == 0) { |
131 bih->biCompression = sh_video->format | |
132 = mmioFOURCC('H','2','6','4'); | |
22852 | 133 unsigned int configLen = 0; |
134 unsigned char* configData | |
135 = parseH264ConfigStr(subsession->fmtp_spropparametersets(), configLen); | |
136 sh_video->bih = bih = insertVideoExtradata(bih, configData, configLen); | |
32142
4614728cab25
build system: Merge all FFmpeg library checks into a single FFmpeg check.
diego
parents:
31627
diff
changeset
|
137 #ifdef CONFIG_FFMPEG |
31071
adf57737978c
Silence permanent warning messages when decoding H264 over rtsp with
cehoyos
parents:
29892
diff
changeset
|
138 int fooLen; |
adf57737978c
Silence permanent warning messages when decoding H264 over rtsp with
cehoyos
parents:
29892
diff
changeset
|
139 const uint8_t* fooData; |
24103
d44e23b469a3
Fix compilation of live555 support after FFmpegs r10173.
cehoyos
parents:
22852
diff
changeset
|
140 avcodec_register_all(); |
22852 | 141 h264parserctx = av_parser_init(CODEC_ID_H264); |
29451
6aca83f5ba73
Fix a crash when playing some H264 over rtsp streams: Do pass an
cehoyos
parents:
29448
diff
changeset
|
142 avcctx = avcodec_alloc_context(); |
31071
adf57737978c
Silence permanent warning messages when decoding H264 over rtsp with
cehoyos
parents:
29892
diff
changeset
|
143 // Pass the config to the parser |
adf57737978c
Silence permanent warning messages when decoding H264 over rtsp with
cehoyos
parents:
29892
diff
changeset
|
144 h264parserctx->parser->parser_parse(h264parserctx, avcctx, |
adf57737978c
Silence permanent warning messages when decoding H264 over rtsp with
cehoyos
parents:
29892
diff
changeset
|
145 &fooData, &fooLen, configData, configLen); |
22852 | 146 #endif |
31071
adf57737978c
Silence permanent warning messages when decoding H264 over rtsp with
cehoyos
parents:
29892
diff
changeset
|
147 delete[] configData; |
19415 | 148 needVideoFrameRate(demuxer, subsession); |
9250 | 149 } else if (strcmp(subsession->codecName(), "H261") == 0) { |
150 bih->biCompression = sh_video->format | |
151 = mmioFOURCC('H','2','6','1'); | |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
152 needVideoFrameRate(demuxer, subsession); |
9370
88bd19564b64
Motion-JPEG RTP streams can now be played. Some MPEG-4 ES video RTP
arpi
parents:
9250
diff
changeset
|
153 } else if (strcmp(subsession->codecName(), "JPEG") == 0) { |
88bd19564b64
Motion-JPEG RTP streams can now be played. Some MPEG-4 ES video RTP
arpi
parents:
9250
diff
changeset
|
154 bih->biCompression = sh_video->format |
88bd19564b64
Motion-JPEG RTP streams can now be played. Some MPEG-4 ES video RTP
arpi
parents:
9250
diff
changeset
|
155 = mmioFOURCC('M','J','P','G'); |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
156 needVideoFrameRate(demuxer, subsession); |
9370
88bd19564b64
Motion-JPEG RTP streams can now be played. Some MPEG-4 ES video RTP
arpi
parents:
9250
diff
changeset
|
157 } else if (strcmp(subsession->codecName(), "MP4V-ES") == 0) { |
88bd19564b64
Motion-JPEG RTP streams can now be played. Some MPEG-4 ES video RTP
arpi
parents:
9250
diff
changeset
|
158 bih->biCompression = sh_video->format |
88bd19564b64
Motion-JPEG RTP streams can now be played. Some MPEG-4 ES video RTP
arpi
parents:
9250
diff
changeset
|
159 = mmioFOURCC('m','p','4','v'); |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
160 // For the codec to work correctly, it may need a 'VOL Header' to be |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
161 // inserted at the front of the data stream. Construct this from the |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
162 // "config" MIME parameter, which was present (hopefully) in the |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
163 // session's SDP description: |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
164 unsigned configLen; |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
165 unsigned char* configData |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
166 = parseGeneralConfigStr(subsession->fmtp_config(), configLen); |
22278
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
167 sh_video->bih = bih = insertVideoExtradata(bih, configData, configLen); |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
168 needVideoFrameRate(demuxer, subsession); |
9250 | 169 } else if (strcmp(subsession->codecName(), "X-QT") == 0 || |
170 strcmp(subsession->codecName(), "X-QUICKTIME") == 0) { | |
171 // QuickTime generic RTP format, as described in | |
172 // http://developer.apple.com/quicktime/icefloe/dispatch026.html | |
173 | |
174 // We can't initialize this stream until we've received the first packet | |
175 // that has QuickTime "sdAtom" information in the header. So, keep | |
176 // reading packets until we get one: | |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
177 unsigned char* packetData; unsigned packetDataLen; float pts; |
9250 | 178 QuickTimeGenericRTPSource* qtRTPSource |
179 = (QuickTimeGenericRTPSource*)(subsession->rtpSource()); | |
180 unsigned fourcc; | |
181 do { | |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
182 if (!awaitRTPPacket(demuxer, demuxer->video, |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
183 packetData, packetDataLen, pts)) { |
9250 | 184 return; |
185 } | |
186 } while (!parseQTState_video(qtRTPSource->qtState, fourcc)); | |
187 | |
188 bih->biCompression = sh_video->format = fourcc; | |
21871 | 189 bih->biWidth = qtRTPSource->qtState.width; |
190 bih->biHeight = qtRTPSource->qtState.height; | |
29435 | 191 if (qtRTPSource->qtState.sdAtomSize > 83) |
192 bih->biBitCount = qtRTPSource->qtState.sdAtom[83]; | |
21871 | 193 uint8_t *pos = (uint8_t*)qtRTPSource->qtState.sdAtom + 86; |
194 uint8_t *endpos = (uint8_t*)qtRTPSource->qtState.sdAtom | |
195 + qtRTPSource->qtState.sdAtomSize; | |
196 while (pos+8 < endpos) { | |
197 unsigned atomLength = pos[0]<<24 | pos[1]<<16 | pos[2]<<8 | pos[3]; | |
198 if (atomLength == 0 || atomLength > endpos-pos) break; | |
29892
ecf6cbab0b8d
Silence two gcc warnings: suggest parentheses around && within ||
cehoyos
parents:
29453
diff
changeset
|
199 if (((!memcmp(pos+4, "avcC", 4) && fourcc==mmioFOURCC('a','v','c','1')) || |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29238
diff
changeset
|
200 !memcmp(pos+4, "esds", 4) || |
29892
ecf6cbab0b8d
Silence two gcc warnings: suggest parentheses around && within ||
cehoyos
parents:
29453
diff
changeset
|
201 (!memcmp(pos+4, "SMI ", 4) && fourcc==mmioFOURCC('S','V','Q','3'))) && |
22278
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
202 atomLength > 8) { |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29238
diff
changeset
|
203 sh_video->bih = bih = |
22278
ac8ac9e3761d
insert extradata in sh_video->bih+1 instead of pushing it to demuxer->video as separate packet; patch by C.E.Hoyos
nicodvb
parents:
22235
diff
changeset
|
204 insertVideoExtradata(bih, pos+8, atomLength-8); |
21871 | 205 break; |
206 } | |
207 pos += atomLength; | |
208 } | |
22756
3d6a64f3d28f
Every X-QT stream needs video frame rate (not just avc, mpeg4 and svq3)
cehoyos
parents:
22463
diff
changeset
|
209 needVideoFrameRate(demuxer, subsession); |
9250 | 210 } else { |
211 fprintf(stderr, | |
212 "Unknown MPlayer format code for MIME type \"video/%s\"\n", | |
213 subsession->codecName()); | |
214 } | |
215 } | |
216 | |
217 void rtpCodecInitialize_audio(demuxer_t* demuxer, | |
218 MediaSubsession* subsession, | |
219 unsigned& flags) { | |
220 flags = 0; | |
221 // Create a dummy audio stream header | |
222 // to make the main MPlayer code happy: | |
31627 | 223 sh_audio_t* sh_audio = new_sh_audio(demuxer,0, NULL); |
9250 | 224 WAVEFORMATEX* wf = (WAVEFORMATEX*)calloc(1,sizeof(WAVEFORMATEX)); |
225 sh_audio->wf = wf; | |
226 demux_stream_t* d_audio = demuxer->audio; | |
227 d_audio->sh = sh_audio; sh_audio->ds = d_audio; | |
27417 | 228 d_audio->id = sh_audio->aid; |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29238
diff
changeset
|
229 |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
230 wf->nChannels = subsession->numChannels(); |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
231 |
9250 | 232 // Map known audio MIME types to the WAVEFORMATEX parameters |
233 // that this program uses. (Note that not all types need all | |
234 // of the parameters to be set.) | |
235 wf->nSamplesPerSec | |
236 = subsession->rtpSource()->timestampFrequency(); // by default | |
237 if (strcmp(subsession->codecName(), "MPA") == 0 || | |
238 strcmp(subsession->codecName(), "MPA-ROBUST") == 0 || | |
239 strcmp(subsession->codecName(), "X-MP3-DRAFT-00") == 0) { | |
240 wf->wFormatTag = sh_audio->format = 0x55; | |
241 // Note: 0x55 is for layer III, but should work for I,II also | |
242 wf->nSamplesPerSec = 0; // sample rate is deduced from the data | |
243 } else if (strcmp(subsession->codecName(), "AC3") == 0) { | |
244 wf->wFormatTag = sh_audio->format = 0x2000; | |
245 wf->nSamplesPerSec = 0; // sample rate is deduced from the data | |
10478
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
246 } else if (strcmp(subsession->codecName(), "L16") == 0) { |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
247 wf->wFormatTag = sh_audio->format = 0x736f7774; // "twos" |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
248 wf->nBlockAlign = 1; |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
249 wf->wBitsPerSample = 16; |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
250 wf->cbSize = 0; |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
251 } else if (strcmp(subsession->codecName(), "L8") == 0) { |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
252 wf->wFormatTag = sh_audio->format = 0x20776172; // "raw " |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
253 wf->nBlockAlign = 1; |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
254 wf->wBitsPerSample = 8; |
b0d0aa726417
Added support for the "L16" and "L8" (raw PCM audio) RTP payload formats.
rsf
parents:
9910
diff
changeset
|
255 wf->cbSize = 0; |
9250 | 256 } else if (strcmp(subsession->codecName(), "PCMU") == 0) { |
257 wf->wFormatTag = sh_audio->format = 0x7; | |
258 wf->nAvgBytesPerSec = 8000; | |
259 wf->nBlockAlign = 1; | |
260 wf->wBitsPerSample = 8; | |
261 wf->cbSize = 0; | |
262 } else if (strcmp(subsession->codecName(), "PCMA") == 0) { | |
263 wf->wFormatTag = sh_audio->format = 0x6; | |
264 wf->nAvgBytesPerSec = 8000; | |
265 wf->nBlockAlign = 1; | |
266 wf->wBitsPerSample = 8; | |
267 wf->cbSize = 0; | |
22463
979b2aa16e80
support for AMR; it works inserting in the first byte of the demux_packet
nicodvb
parents:
22354
diff
changeset
|
268 } else if (strcmp(subsession->codecName(), "AMR") == 0) { |
979b2aa16e80
support for AMR; it works inserting in the first byte of the demux_packet
nicodvb
parents:
22354
diff
changeset
|
269 wf->wFormatTag = sh_audio->format = mmioFOURCC('s','a','m','r'); |
979b2aa16e80
support for AMR; it works inserting in the first byte of the demux_packet
nicodvb
parents:
22354
diff
changeset
|
270 } else if (strcmp(subsession->codecName(), "AMR-WB") == 0) { |
979b2aa16e80
support for AMR; it works inserting in the first byte of the demux_packet
nicodvb
parents:
22354
diff
changeset
|
271 wf->wFormatTag = sh_audio->format = mmioFOURCC('s','a','w','b'); |
9250 | 272 } else if (strcmp(subsession->codecName(), "GSM") == 0) { |
273 wf->wFormatTag = sh_audio->format = mmioFOURCC('a','g','s','m'); | |
274 wf->nAvgBytesPerSec = 1650; | |
275 wf->nBlockAlign = 33; | |
276 wf->wBitsPerSample = 16; | |
277 wf->cbSize = 0; | |
278 } else if (strcmp(subsession->codecName(), "QCELP") == 0) { | |
279 wf->wFormatTag = sh_audio->format = mmioFOURCC('Q','c','l','p'); | |
280 wf->nAvgBytesPerSec = 1750; | |
281 wf->nBlockAlign = 35; | |
282 wf->wBitsPerSample = 16; | |
283 wf->cbSize = 0; | |
284 } else if (strcmp(subsession->codecName(), "MP4A-LATM") == 0) { | |
285 wf->wFormatTag = sh_audio->format = mmioFOURCC('m','p','4','a'); | |
286 // For the codec to work correctly, it needs "AudioSpecificConfig" | |
287 // data, which is parsed from the "StreamMuxConfig" string that | |
288 // was present (hopefully) in the SDP description: | |
289 unsigned codecdata_len; | |
290 sh_audio->codecdata | |
291 = parseStreamMuxConfigStr(subsession->fmtp_config(), | |
292 codecdata_len); | |
293 sh_audio->codecdata_len = codecdata_len; | |
22235
583926af08ac
omit length field of AAC-LATM audio streams; fixes decoding by faad. Patch by Carl Eugen Hoyos (cehoyos ag or at)
nicodvb
parents:
22211
diff
changeset
|
294 //faad doesn't understand LATM's data length field, so omit it |
583926af08ac
omit length field of AAC-LATM audio streams; fixes decoding by faad. Patch by Carl Eugen Hoyos (cehoyos ag or at)
nicodvb
parents:
22211
diff
changeset
|
295 ((MPEG4LATMAudioRTPSource*)subsession->rtpSource())->omitLATMDataLengthField(); |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
296 } else if (strcmp(subsession->codecName(), "MPEG4-GENERIC") == 0) { |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
297 wf->wFormatTag = sh_audio->format = mmioFOURCC('m','p','4','a'); |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
298 // For the codec to work correctly, it needs "AudioSpecificConfig" |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
299 // data, which was present (hopefully) in the SDP description: |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
300 unsigned codecdata_len; |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
301 sh_audio->codecdata |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
302 = parseGeneralConfigStr(subsession->fmtp_config(), |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
303 codecdata_len); |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
304 sh_audio->codecdata_len = codecdata_len; |
9250 | 305 } else if (strcmp(subsession->codecName(), "X-QT") == 0 || |
306 strcmp(subsession->codecName(), "X-QUICKTIME") == 0) { | |
307 // QuickTime generic RTP format, as described in | |
308 // http://developer.apple.com/quicktime/icefloe/dispatch026.html | |
309 | |
310 // We can't initialize this stream until we've received the first packet | |
311 // that has QuickTime "sdAtom" information in the header. So, keep | |
312 // reading packets until we get one: | |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
313 unsigned char* packetData; unsigned packetDataLen; float pts; |
9250 | 314 QuickTimeGenericRTPSource* qtRTPSource |
315 = (QuickTimeGenericRTPSource*)(subsession->rtpSource()); | |
316 unsigned fourcc, numChannels; | |
317 do { | |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
318 if (!awaitRTPPacket(demuxer, demuxer->audio, |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
319 packetData, packetDataLen, pts)) { |
9250 | 320 return; |
321 } | |
322 } while (!parseQTState_audio(qtRTPSource->qtState, fourcc, numChannels)); | |
323 | |
324 wf->wFormatTag = sh_audio->format = fourcc; | |
325 wf->nChannels = numChannels; | |
22336
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
326 |
29448
80c6dd85f7f8
Parse BitsPerSample and SamplesPerSec when playing PCM in X-QT over
cehoyos
parents:
29435
diff
changeset
|
327 if (qtRTPSource->qtState.sdAtomSize > 33) { |
80c6dd85f7f8
Parse BitsPerSample and SamplesPerSec when playing PCM in X-QT over
cehoyos
parents:
29435
diff
changeset
|
328 wf->wBitsPerSample = qtRTPSource->qtState.sdAtom[27]; |
80c6dd85f7f8
Parse BitsPerSample and SamplesPerSec when playing PCM in X-QT over
cehoyos
parents:
29435
diff
changeset
|
329 wf->nSamplesPerSec = qtRTPSource->qtState.sdAtom[32]<<8|qtRTPSource->qtState.sdAtom[33]; |
80c6dd85f7f8
Parse BitsPerSample and SamplesPerSec when playing PCM in X-QT over
cehoyos
parents:
29435
diff
changeset
|
330 } |
22336
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
331 uint8_t *pos = (uint8_t*)qtRTPSource->qtState.sdAtom + 52; |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
332 uint8_t *endpos = (uint8_t*)qtRTPSource->qtState.sdAtom |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
333 + qtRTPSource->qtState.sdAtomSize; |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
334 while (pos+8 < endpos) { |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
335 unsigned atomLength = pos[0]<<24 | pos[1]<<16 | pos[2]<<8 | pos[3]; |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
336 if (atomLength == 0 || atomLength > endpos-pos) break; |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
337 if (!memcmp(pos+4, "wave", 4) && fourcc==mmioFOURCC('Q','D','M','2') && |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
338 atomLength > 8 && |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
339 atomLength <= INT_MAX) { |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
340 sh_audio->codecdata = (unsigned char*) malloc(atomLength-8); |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
341 if (sh_audio->codecdata) { |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
342 memcpy(sh_audio->codecdata, pos+8, atomLength-8); |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
343 sh_audio->codecdata_len = atomLength-8; |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
344 } |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
345 break; |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
346 } |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
347 pos += atomLength; |
760c74c078ce
copy the content of QDM2 atom as extradata for ffqdm2 playback; patch by Carl Eugen Hoyos
nicodvb
parents:
22278
diff
changeset
|
348 } |
9250 | 349 } else { |
350 fprintf(stderr, | |
351 "Unknown MPlayer format code for MIME type \"audio/%s\"\n", | |
352 subsession->codecName()); | |
353 } | |
354 } | |
355 | |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
356 static void needVideoFrameRate(demuxer_t* demuxer, |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
357 MediaSubsession* subsession) { |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
358 // For some codecs, MPlayer's decoding software can't (or refuses to :-) |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
359 // figure out the frame rate by itself, so (unless the user specifies |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
360 // it manually, using "-fps") we figure it out ourselves here, using the |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
361 // presentation timestamps in successive packets, |
25965 | 362 extern double force_fps; if (force_fps != 0.0) return; // user used "-fps" |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
363 |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
364 demux_stream_t* d_video = demuxer->video; |
9910 | 365 sh_video_t* sh_video = (sh_video_t*)(d_video->sh); |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
366 |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
367 // If we already know the subsession's video frame rate, use it: |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
368 int fps = (int)(subsession->videoFPS()); |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
369 if (fps != 0) { |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
370 sh_video->fps = fps; |
22354
b465e5be1a53
assign missing frametime as 1.0/fps; patch by Carl Eigen Hoyos
nicodvb
parents:
22336
diff
changeset
|
371 sh_video->frametime = 1.0f/fps; |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
372 return; |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
373 } |
29263
0f1b5b68af32
whitespace cosmetics: Remove all trailing whitespace.
diego
parents:
29238
diff
changeset
|
374 |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
375 // Keep looking at incoming frames until we see two with different, |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
376 // non-zero "pts" timestamps: |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
377 unsigned char* packetData; unsigned packetDataLen; |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
378 float lastPTS = 0.0, curPTS; |
11397
d0db11b74e82
Increased the threshold for how many incoming frames to look at while guessing
rsf
parents:
10478
diff
changeset
|
379 unsigned const maxNumFramesToWaitFor = 300; |
21983
a6b624360aef
better autodetection of framerate in case of h264; it works correctly with b-frames.
nicodvb
parents:
21911
diff
changeset
|
380 int lastfps = 0; |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
381 for (unsigned i = 0; i < maxNumFramesToWaitFor; ++i) { |
9910 | 382 if (!awaitRTPPacket(demuxer, d_video, packetData, packetDataLen, curPTS)) { |
383 break; | |
384 } | |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
385 |
21983
a6b624360aef
better autodetection of framerate in case of h264; it works correctly with b-frames.
nicodvb
parents:
21911
diff
changeset
|
386 if (curPTS != lastPTS && lastPTS != 0.0) { |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
387 // Use the difference between these two "pts"s to guess the frame rate. |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
388 // (should really check that there were no missing frames inbetween)##### |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
389 // Guess the frame rate as an integer. If it's not, use "-fps" instead. |
21983
a6b624360aef
better autodetection of framerate in case of h264; it works correctly with b-frames.
nicodvb
parents:
21911
diff
changeset
|
390 fps = (int)(1/fabs(curPTS-lastPTS) + 0.5); // rounding |
a6b624360aef
better autodetection of framerate in case of h264; it works correctly with b-frames.
nicodvb
parents:
21911
diff
changeset
|
391 if (fps == lastfps) { |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
392 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); |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
393 sh_video->fps = fps; |
21983
a6b624360aef
better autodetection of framerate in case of h264; it works correctly with b-frames.
nicodvb
parents:
21911
diff
changeset
|
394 sh_video->frametime=1.0f/fps; |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
395 return; |
21983
a6b624360aef
better autodetection of framerate in case of h264; it works correctly with b-frames.
nicodvb
parents:
21911
diff
changeset
|
396 } |
a6b624360aef
better autodetection of framerate in case of h264; it works correctly with b-frames.
nicodvb
parents:
21911
diff
changeset
|
397 if (fps>lastfps) lastfps = fps; |
9565
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
398 } |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
399 lastPTS = curPTS; |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
400 } |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
401 fprintf(stderr, "demux_rtp: Failed to guess the video frame rate\n"); |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
402 } |
e74916774667
Improved RTP packet buffering, by relying on the underlying OS's UDP
rsf
parents:
9370
diff
changeset
|
403 |
9250 | 404 static Boolean |
405 parseQTState_video(QuickTimeGenericRTPSource::QTState const& qtState, | |
406 unsigned& fourcc) { | |
407 // qtState's "sdAtom" field is supposed to contain a QuickTime video | |
408 // 'sample description' atom. This atom's name is the 'fourcc' that we want: | |
409 char const* sdAtom = qtState.sdAtom; | |
410 if (sdAtom == NULL || qtState.sdAtomSize < 2*4) return False; | |
411 | |
412 fourcc = *(unsigned*)(&sdAtom[4]); // put in host order | |
413 return True; | |
414 } | |
415 | |
416 static Boolean | |
417 parseQTState_audio(QuickTimeGenericRTPSource::QTState const& qtState, | |
418 unsigned& fourcc, unsigned& numChannels) { | |
419 // qtState's "sdAtom" field is supposed to contain a QuickTime audio | |
420 // 'sample description' atom. This atom's name is the 'fourcc' that we want. | |
421 // Also, the top half of the 5th word following the atom name should | |
422 // contain the number of channels ("numChannels") that we want: | |
423 char const* sdAtom = qtState.sdAtom; | |
424 if (sdAtom == NULL || qtState.sdAtomSize < 7*4) return False; | |
425 | |
426 fourcc = *(unsigned*)(&sdAtom[4]); // put in host order | |
427 | |
428 char const* word7Ptr = &sdAtom[6*4]; | |
429 numChannels = (word7Ptr[0]<<8)|(word7Ptr[1]); | |
430 return True; | |
431 } |