options: Make dynamic dup hack work with new options
[mplayer.git] / libmpdemux / demux_aac.c
blob88d9204615da7ed27aa188ef5f8fae5f9d6ad022
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
5 #include "config.h"
6 #include "mp_msg.h"
7 #include "help_mp.h"
9 #include "stream/stream.h"
10 #include "demuxer.h"
11 #include "parse_es.h"
12 #include "stheader.h"
14 #include "ms_hdr.h"
16 typedef struct {
17 uint8_t *buf;
18 uint64_t size; /// amount of time of data packets pushed to demuxer->audio (in bytes)
19 float time; /// amount of time elapsed based upon samples_per_frame/sample_rate (in milliseconds)
20 float last_pts; /// last pts seen
21 int bitrate; /// bitrate computed as size/time
22 } aac_priv_t;
24 /// \param srate (out) sample rate
25 /// \param num (out) number of audio frames in this ADTS frame
26 /// \return size of the ADTS frame in bytes
27 /// aac_parse_frames needs a buffer at least 8 bytes long
28 int aac_parse_frame(uint8_t *buf, int *srate, int *num);
30 static int demux_aac_init(demuxer_t *demuxer)
32 aac_priv_t *priv;
34 priv = calloc(1, sizeof(aac_priv_t));
35 if(!priv)
36 return 0;
38 priv->buf = (uint8_t*) malloc(8);
39 if(!priv->buf)
41 free(priv);
42 return 0;
45 demuxer->priv = priv;
46 return 1;
49 static void demux_close_aac(demuxer_t *demuxer)
51 aac_priv_t *priv = (aac_priv_t *) demuxer->priv;
53 if(!priv)
54 return;
56 if(priv->buf)
57 free(priv->buf);
59 free(demuxer->priv);
61 return;
64 /// returns DEMUXER_TYPE_AAC if it finds 8 ADTS frames in 32768 bytes, 0 otherwise
65 static int demux_aac_probe(demuxer_t *demuxer)
67 int cnt = 0, c, len, srate, num;
68 off_t init, probed;
69 aac_priv_t *priv;
71 if(! demux_aac_init(demuxer))
73 mp_msg(MSGT_DEMUX, MSGL_ERR, "COULDN'T INIT aac_demux, exit\n");
74 return 0;
77 priv = (aac_priv_t *) demuxer->priv;
79 init = probed = stream_tell(demuxer->stream);
80 while(probed-init <= 32768 && cnt < 8)
82 c = 0;
83 while(c != 0xFF)
85 c = stream_read_char(demuxer->stream);
86 if(c < 0)
87 goto fail;
89 priv->buf[0] = 0xFF;
90 if(stream_read(demuxer->stream, &(priv->buf[1]), 7) < 7)
91 goto fail;
93 len = aac_parse_frame(priv->buf, &srate, &num);
94 if(len > 0)
96 cnt++;
97 stream_skip(demuxer->stream, len - 8);
99 probed = stream_tell(demuxer->stream);
102 stream_seek(demuxer->stream, init);
103 if(cnt < 8)
104 goto fail;
106 mp_msg(MSGT_DEMUX, MSGL_V, "demux_aac_probe, INIT: %"PRIu64", PROBED: %"PRIu64", cnt: %d\n", init, probed, cnt);
107 return DEMUXER_TYPE_AAC;
109 fail:
110 mp_msg(MSGT_DEMUX, MSGL_V, "demux_aac_probe, failed to detect an AAC stream\n");
111 return 0;
114 static demuxer_t* demux_aac_open(demuxer_t *demuxer)
116 sh_audio_t *sh;
118 sh = new_sh_audio(demuxer, 0);
119 sh->ds = demuxer->audio;
120 sh->format = mmioFOURCC('M', 'P', '4', 'A');
121 demuxer->audio->id = 0;
122 demuxer->audio->sh = sh;
124 demuxer->filepos = stream_tell(demuxer->stream);
126 return demuxer;
129 static int demux_aac_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds)
131 aac_priv_t *priv = (aac_priv_t *) demuxer->priv;
132 demux_packet_t *dp;
133 int c1, c2, len, srate, num;
134 float tm = 0;
136 if(demuxer->stream->eof || (demuxer->movi_end && stream_tell(demuxer->stream) >= demuxer->movi_end))
137 return 0;
139 while(! demuxer->stream->eof)
141 c1 = c2 = 0;
142 while(c1 != 0xFF)
144 c1 = stream_read_char(demuxer->stream);
145 if(c1 < 0)
146 return 0;
148 c2 = stream_read_char(demuxer->stream);
149 if(c2 < 0)
150 return 0;
151 if((c2 & 0xF6) != 0xF0)
152 continue;
154 priv->buf[0] = (unsigned char) c1;
155 priv->buf[1] = (unsigned char) c2;
156 if(stream_read(demuxer->stream, &(priv->buf[2]), 6) < 6)
157 return 0;
159 len = aac_parse_frame(priv->buf, &srate, &num);
160 if(len > 0)
162 dp = new_demux_packet(len);
163 if(! dp)
165 mp_msg(MSGT_DEMUX, MSGL_ERR, "fill_buffer, NEW_ADD_PACKET(%d)FAILED\n", len);
166 return 0;
170 memcpy(dp->buffer, priv->buf, 8);
171 stream_read(demuxer->stream, &(dp->buffer[8]), len-8);
172 if(srate)
173 tm = (float) (num * 1024.0/srate);
174 priv->last_pts += tm;
175 dp->pts = priv->last_pts;
176 //fprintf(stderr, "\nPTS: %.3f\n", dp->pts);
177 ds_add_packet(demuxer->audio, dp);
178 priv->size += len;
179 priv->time += tm;
181 priv->bitrate = (int) (priv->size / priv->time);
182 demuxer->filepos = stream_tell(demuxer->stream);
184 return len;
186 else
187 stream_skip(demuxer->stream, -6);
190 return 0;
194 //This is an almost verbatim copy of high_res_mp3_seek(), from demux_audio.c
195 static void demux_aac_seek(demuxer_t *demuxer, float rel_seek_secs, float audio_delay, int flags)
197 aac_priv_t *priv = (aac_priv_t *) demuxer->priv;
198 demux_stream_t *d_audio=demuxer->audio;
199 sh_audio_t *sh_audio=d_audio->sh;
200 float time;
202 ds_free_packs(d_audio);
204 time = (flags & SEEK_ABSOLUTE) ? rel_seek_secs - priv->last_pts : rel_seek_secs;
205 if(time < 0)
207 stream_seek(demuxer->stream, demuxer->movi_start);
208 time = priv->last_pts + time;
209 priv->last_pts = 0;
212 if(time > 0)
214 int len, nf, srate, num;
216 nf = time * sh_audio->samplerate/1024;
218 while(nf > 0)
220 if(stream_read(demuxer->stream,priv->buf, 8) < 8)
221 break;
222 len = aac_parse_frame(priv->buf, &srate, &num);
223 if(len <= 0)
225 stream_skip(demuxer->stream, -7);
226 continue;
228 stream_skip(demuxer->stream, len - 8);
229 priv->last_pts += (float) (num*1024.0/srate);
230 nf -= num;
236 const demuxer_desc_t demuxer_desc_aac = {
237 "AAC demuxer",
238 "aac",
239 "AAC",
240 "Nico Sabbi",
241 "Raw AAC files ",
242 DEMUXER_TYPE_AAC,
243 0, // unsafe autodetect
244 demux_aac_probe,
245 demux_aac_fill_buffer,
246 demux_aac_open,
247 demux_close_aac,
248 demux_aac_seek,
249 NULL