this is a FIXME
[swfdec.git] / swfdec / swfdec_flv_decoder.c
blob29c6817e23073b7d571647d3a7ea122e1ebbfd9f
1 /* Swfdec
2 * Copyright (C) 2007 Benjamin Otte <otte@gnome.org>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301 USA
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
24 #include "swfdec_flv_decoder.h"
25 #include "swfdec_audio_decoder.h"
26 #include "swfdec_audio_internal.h"
27 #include "swfdec_bits.h"
28 #include "swfdec_debug.h"
29 #include "swfdec_player_internal.h"
30 #include "swfdec_video_decoder.h"
32 enum {
33 SWFDEC_STATE_HEADER, /* need to parse header */
34 SWFDEC_STATE_LAST_TAG, /* read size of last tag */
35 SWFDEC_STATE_TAG, /* read next tag */
36 SWFDEC_STATE_EOF /* file is complete */
39 typedef struct _SwfdecFlvVideoTag SwfdecFlvVideoTag;
40 typedef struct _SwfdecFlvAudioTag SwfdecFlvAudioTag;
41 typedef struct _SwfdecFlvDataTag SwfdecFlvDataTag;
43 struct _SwfdecFlvVideoTag {
44 guint timestamp; /* milliseconds */
45 guint format; /* format in use */
46 int frame_type; /* 0: undefined, 1: keyframe, 2: iframe, 3: H263 disposable iframe */
47 SwfdecBuffer * buffer; /* buffer for this data */
50 struct _SwfdecFlvAudioTag {
51 guint timestamp; /* milliseconds */
52 guint format; /* format in use */
53 SwfdecAudioFormat original_format; /* channel/rate information */
54 SwfdecBuffer * buffer; /* buffer for this data */
57 struct _SwfdecFlvDataTag {
58 guint timestamp; /* milliseconds */
59 SwfdecBuffer * buffer; /* buffer containing raw AMF data */
62 G_DEFINE_TYPE (SwfdecFlvDecoder, swfdec_flv_decoder, SWFDEC_TYPE_DECODER)
64 static void
65 swfdec_flv_decoder_dispose (GObject *object)
67 SwfdecFlvDecoder *flv = SWFDEC_FLV_DECODER (object);
68 guint i;
70 if (flv->audio) {
71 for (i = 0; i < flv->audio->len; i++) {
72 SwfdecFlvAudioTag *tag = &g_array_index (flv->audio, SwfdecFlvAudioTag, i);
73 swfdec_buffer_unref (tag->buffer);
75 g_array_free (flv->audio, TRUE);
76 flv->audio = NULL;
78 if (flv->video) {
79 for (i = 0; i < flv->video->len; i++) {
80 SwfdecFlvVideoTag *tag = &g_array_index (flv->video, SwfdecFlvVideoTag, i);
81 swfdec_buffer_unref (tag->buffer);
83 g_array_free (flv->video, TRUE);
84 flv->video = NULL;
86 if (flv->data) {
87 for (i = 0; i < flv->data->len; i++) {
88 SwfdecFlvDataTag *tag = &g_array_index (flv->data, SwfdecFlvDataTag, i);
89 swfdec_buffer_unref (tag->buffer);
91 g_array_free (flv->data, TRUE);
92 flv->data = NULL;
94 swfdec_buffer_queue_unref (flv->queue);
95 flv->queue = NULL;
97 G_OBJECT_CLASS (swfdec_flv_decoder_parent_class)->dispose (object);
100 static SwfdecStatus
101 swfdec_flv_decoder_parse_header (SwfdecFlvDecoder *flv)
103 SwfdecBuffer *buffer;
104 SwfdecBits bits;
105 guint version, header_length;
106 gboolean has_audio, has_video;
108 buffer = swfdec_buffer_queue_peek (flv->queue, 9);
109 if (buffer == NULL)
110 return SWFDEC_STATUS_NEEDBITS;
112 swfdec_bits_init (&bits, buffer);
113 /* Check if we're really an FLV file */
114 if (swfdec_bits_get_u8 (&bits) != 'F' ||
115 swfdec_bits_get_u8 (&bits) != 'L' ||
116 swfdec_bits_get_u8 (&bits) != 'V') {
117 swfdec_buffer_unref (buffer);
118 return SWFDEC_STATUS_ERROR;
121 version = swfdec_bits_get_u8 (&bits);
122 swfdec_bits_getbits (&bits, 5);
123 has_audio = swfdec_bits_getbit (&bits);
124 swfdec_bits_getbit (&bits);
125 has_video = swfdec_bits_getbit (&bits);
126 header_length = swfdec_bits_get_bu32 (&bits);
127 swfdec_buffer_unref (buffer);
128 if (header_length < 9) {
129 SWFDEC_ERROR ("invalid header length %u, must be 9 or greater", header_length);
130 /* FIXME: treat as error or ignore? */
131 return SWFDEC_STATUS_ERROR;
133 buffer = swfdec_buffer_queue_pull (flv->queue, header_length);
134 if (buffer == NULL)
135 return SWFDEC_STATUS_NEEDBITS;
136 swfdec_buffer_unref (buffer);
137 SWFDEC_LOG ("parsing flv stream");
138 SWFDEC_LOG (" version %u", version);
139 SWFDEC_LOG (" with%s audio", has_audio ? "" : "out");
140 SWFDEC_LOG (" with%s video", has_video ? "" : "out");
141 flv->version = version;
142 if (has_audio) {
143 flv->audio = g_array_new (FALSE, FALSE, sizeof (SwfdecFlvAudioTag));
145 if (has_video) {
146 flv->video = g_array_new (FALSE, FALSE, sizeof (SwfdecFlvVideoTag));
148 flv->state = SWFDEC_STATE_LAST_TAG;
150 return SWFDEC_STATUS_OK;
153 static SwfdecStatus
154 swfdec_flv_decoder_parse_last_tag (SwfdecFlvDecoder *flv)
156 SwfdecBuffer *buffer;
157 SwfdecBits bits;
158 guint last_tag;
160 buffer = swfdec_buffer_queue_pull (flv->queue, 4);
161 if (buffer == NULL)
162 return SWFDEC_STATUS_NEEDBITS;
164 swfdec_bits_init (&bits, buffer);
165 last_tag = swfdec_bits_get_bu32 (&bits);
166 SWFDEC_LOG ("last tag was %u bytes", last_tag);
167 swfdec_buffer_unref (buffer);
168 flv->state = SWFDEC_STATE_TAG;
169 return SWFDEC_STATUS_OK;
172 static guint
173 swfdec_flv_decoder_find_video (SwfdecFlvDecoder *flv, guint timestamp)
175 guint min, max;
177 g_assert (flv->video);
179 min = 0;
180 max = flv->video->len;
181 while (max - min > 1) {
182 guint cur = (max + min) / 2;
183 SwfdecFlvVideoTag *tag = &g_array_index (flv->video, SwfdecFlvVideoTag, cur);
184 if (tag->timestamp > timestamp) {
185 max = cur;
186 } else {
187 min = cur;
190 return min;
193 static guint
194 swfdec_flv_decoder_find_audio (SwfdecFlvDecoder *flv, guint timestamp)
196 guint min, max;
198 g_assert (flv->audio);
200 min = 0;
201 max = flv->audio->len;
202 while (max - min > 1) {
203 guint cur = (max + min) / 2;
204 SwfdecFlvAudioTag *tag = &g_array_index (flv->audio, SwfdecFlvAudioTag, cur);
205 if (tag->timestamp > timestamp) {
206 max = cur;
207 } else {
208 min = cur;
211 return min;
214 static guint
215 swfdec_flv_decoder_find_data (SwfdecFlvDecoder *flv, guint timestamp)
217 guint min, max;
219 g_assert (flv->data);
221 min = 0;
222 max = flv->data->len;
223 while (max - min > 1) {
224 guint cur = (max + min) / 2;
225 SwfdecFlvDataTag *tag = &g_array_index (flv->data, SwfdecFlvDataTag, cur);
226 if (tag->timestamp > timestamp) {
227 max = cur;
228 } else {
229 min = cur;
232 return min;
235 static SwfdecStatus
236 swfdec_flv_decoder_parse_video_tag (SwfdecFlvDecoder *flv, SwfdecBits *bits, guint timestamp)
238 SwfdecFlvVideoTag tag;
240 if (flv->video == NULL) {
241 SWFDEC_INFO ("video tags even though header didn't decalre them. Initializing...");
242 flv->video = g_array_new (FALSE, FALSE, sizeof (SwfdecFlvVideoTag));
243 return SWFDEC_STATUS_OK;
246 tag.timestamp = timestamp;
247 tag.frame_type = swfdec_bits_getbits (bits, 4);
248 tag.format = swfdec_bits_getbits (bits, 4);
249 tag.buffer = swfdec_bits_get_buffer (bits, -1);
250 SWFDEC_LOG (" format: %u", tag.format);
251 SWFDEC_LOG (" frame type: %u", tag.frame_type);
252 if (tag.buffer == NULL) {
253 SWFDEC_WARNING ("no buffer, ignoring");
254 return SWFDEC_STATUS_OK;
256 if (flv->video->len == 0) {
257 g_array_append_val (flv->video, tag);
258 swfdec_decoder_use_video_codec (SWFDEC_DECODER (flv), tag.format);
259 return SWFDEC_STATUS_INIT;
260 } else if (g_array_index (flv->video, SwfdecFlvVideoTag,
261 flv->video->len - 1).timestamp < tag.timestamp) {
262 g_array_append_val (flv->video, tag);
263 } else {
264 guint idx;
265 SWFDEC_WARNING ("timestamps of video buffers not increasing (last was %u, now %u)",
266 g_array_index (flv->video, SwfdecFlvVideoTag, flv->video->len - 1).timestamp,
267 tag.timestamp);
268 idx = swfdec_flv_decoder_find_video (flv, tag.timestamp);
269 g_array_insert_val (flv->video, idx, tag);
271 return SWFDEC_STATUS_IMAGE;
274 static SwfdecStatus
275 swfdec_flv_decoder_parse_audio_tag (SwfdecFlvDecoder *flv, SwfdecBits *bits, guint timestamp)
277 SwfdecFlvAudioTag tag;
279 if (flv->audio == NULL) {
280 SWFDEC_INFO ("audio tags even though header didn't decalre them. Initializing...");
281 flv->audio = g_array_new (FALSE, FALSE, sizeof (SwfdecFlvAudioTag));
282 return SWFDEC_STATUS_OK;
285 tag.timestamp = timestamp;
286 tag.format = swfdec_bits_getbits (bits, 4);
287 tag.original_format = swfdec_audio_format_parse (bits);
288 tag.buffer = swfdec_bits_get_buffer (bits, -1);
289 SWFDEC_LOG (" codec: %u", (guint) tag.format);
290 SWFDEC_LOG (" format: %s", swfdec_audio_format_to_string (tag.original_format));
291 if (tag.buffer == NULL) {
292 SWFDEC_WARNING ("no buffer, ignoring");
293 return SWFDEC_STATUS_OK;
295 if (flv->audio->len == 0) {
296 g_array_append_val (flv->audio, tag);
297 swfdec_decoder_use_audio_codec (SWFDEC_DECODER (flv), tag.format, tag.original_format);
298 return SWFDEC_STATUS_INIT;
299 } else if (g_array_index (flv->audio, SwfdecFlvAudioTag,
300 flv->audio->len - 1).timestamp < tag.timestamp) {
301 g_array_append_val (flv->audio, tag);
302 } else {
303 guint idx;
304 SWFDEC_WARNING ("timestamps of audio buffers not increasing (last was %u, now %u)",
305 g_array_index (flv->audio, SwfdecFlvAudioTag, flv->audio->len - 1).timestamp,
306 tag.timestamp);
307 idx = swfdec_flv_decoder_find_audio (flv, tag.timestamp);
308 g_array_insert_val (flv->audio, idx, tag);
310 return SWFDEC_STATUS_OK;
313 static void
314 swfdec_flv_decoder_parse_data_tag (SwfdecFlvDecoder *flv, SwfdecBits *bits, guint timestamp)
316 SwfdecFlvDataTag tag;
318 if (flv->data == NULL) {
319 flv->data = g_array_new (FALSE, FALSE, sizeof (SwfdecFlvDataTag));
322 tag.timestamp = timestamp;
323 tag.buffer = swfdec_bits_get_buffer (bits, -1);
324 if (tag.buffer == NULL) {
325 SWFDEC_WARNING ("no buffer, ignoring");
326 return;
328 if (flv->data->len == 0) {
329 g_array_append_val (flv->data, tag);
330 } else if (g_array_index (flv->data, SwfdecFlvDataTag,
331 flv->data->len - 1).timestamp < tag.timestamp) {
332 g_array_append_val (flv->data, tag);
333 } else {
334 guint idx;
335 SWFDEC_WARNING ("timestamps of data buffers not increasing (last was %u, now %u)",
336 g_array_index (flv->data, SwfdecFlvDataTag, flv->data->len - 1).timestamp,
337 tag.timestamp);
338 idx = swfdec_flv_decoder_find_data (flv, tag.timestamp);
339 g_array_insert_val (flv->data, idx, tag);
343 static SwfdecStatus
344 swfdec_flv_decoder_parse_tag (SwfdecFlvDecoder *flv)
346 SwfdecBuffer *buffer;
347 SwfdecBits bits;
348 guint size, type, timestamp;
349 SwfdecStatus ret = SWFDEC_STATUS_OK;
351 buffer = swfdec_buffer_queue_peek (flv->queue, 4);
352 if (buffer == NULL)
353 return SWFDEC_STATUS_NEEDBITS;
354 swfdec_bits_init (&bits, buffer);
355 swfdec_bits_get_u8 (&bits);
356 size = swfdec_bits_get_bu24 (&bits);
357 swfdec_buffer_unref (buffer);
358 buffer = swfdec_buffer_queue_pull (flv->queue, 11 + size);
359 if (buffer == NULL)
360 return SWFDEC_STATUS_NEEDBITS;
361 swfdec_bits_init (&bits, buffer);
362 type = swfdec_bits_get_u8 (&bits);
363 /* I think I'm paranoid and complicated. I think I'm paranoid, manipulated */
364 if (size != swfdec_bits_get_bu24 (&bits)) {
365 g_assert_not_reached ();
367 timestamp = swfdec_bits_get_bu24 (&bits);
368 swfdec_bits_get_bu32 (&bits);
369 SWFDEC_LOG ("new tag");
370 SWFDEC_LOG (" type %u", type);
371 SWFDEC_LOG (" size %u", size);
372 SWFDEC_LOG (" timestamp %u", timestamp);
373 switch (type) {
374 case 8:
375 ret = swfdec_flv_decoder_parse_audio_tag (flv, &bits, timestamp);
376 break;
377 case 9:
378 ret = swfdec_flv_decoder_parse_video_tag (flv, &bits, timestamp);
379 break;
380 case 18:
381 swfdec_flv_decoder_parse_data_tag (flv, &bits, timestamp);
382 break;
383 default:
384 SWFDEC_WARNING ("unknown tag (type %u)", type);
385 break;
387 swfdec_buffer_unref (buffer);
388 flv->state = SWFDEC_STATE_LAST_TAG;
389 return ret;
392 static SwfdecStatus
393 swfdec_flv_decoder_parse (SwfdecDecoder *dec, SwfdecBuffer *buffer)
395 SwfdecFlvDecoder *flv = SWFDEC_FLV_DECODER (dec);
396 SwfdecStatus status = 0;
398 swfdec_buffer_queue_push (flv->queue, buffer);
400 do {
401 switch (flv->state) {
402 case SWFDEC_STATE_HEADER:
403 status |= swfdec_flv_decoder_parse_header (flv);
404 break;
405 case SWFDEC_STATE_LAST_TAG:
406 status |= swfdec_flv_decoder_parse_last_tag (flv);
407 break;
408 case SWFDEC_STATE_TAG:
409 status |= swfdec_flv_decoder_parse_tag (flv);
410 break;
411 case SWFDEC_STATE_EOF:
412 status |= SWFDEC_STATUS_EOF;
413 break;
414 default:
415 g_assert_not_reached ();
416 status |= SWFDEC_STATUS_ERROR;
417 break;
419 } while ((status & (SWFDEC_STATUS_EOF | SWFDEC_STATUS_NEEDBITS | SWFDEC_STATUS_ERROR)) == 0);
421 return status;
424 static SwfdecStatus
425 swfdec_flv_decoder_eof (SwfdecDecoder *dec)
427 SwfdecFlvDecoder *flv = SWFDEC_FLV_DECODER (dec);
429 flv->state = SWFDEC_STATE_EOF;
431 return 0;
434 static void
435 swfdec_flv_decoder_class_init (SwfdecFlvDecoderClass *class)
437 GObjectClass *object_class = G_OBJECT_CLASS (class);
438 SwfdecDecoderClass *decoder_class = SWFDEC_DECODER_CLASS (class);
440 object_class->dispose = swfdec_flv_decoder_dispose;
442 decoder_class->parse = swfdec_flv_decoder_parse;
443 decoder_class->eof = swfdec_flv_decoder_eof;
446 static void
447 swfdec_flv_decoder_init (SwfdecFlvDecoder *flv)
449 flv->state = SWFDEC_STATE_HEADER;
450 flv->queue = swfdec_buffer_queue_new ();
453 SwfdecBuffer *
454 swfdec_flv_decoder_get_video (SwfdecFlvDecoder *flv, guint timestamp,
455 gboolean keyframe, guint *format, guint *real_timestamp, guint *next_timestamp)
457 guint id, offset;
458 SwfdecFlvVideoTag *tag;
460 g_return_val_if_fail (SWFDEC_IS_FLV_DECODER (flv), NULL);
461 g_return_val_if_fail (flv->video != NULL, NULL);
463 if (flv->video->len == 0) {
464 if (next_timestamp)
465 *next_timestamp = 0;
466 if (real_timestamp)
467 *real_timestamp = 0;
468 if (format)
469 *format = SWFDEC_VIDEO_CODEC_UNDEFINED;
470 return NULL;
472 offset = g_array_index (flv->video, SwfdecFlvVideoTag, 0).timestamp;
473 timestamp += offset;
474 id = swfdec_flv_decoder_find_video (flv, timestamp);
475 tag = &g_array_index (flv->video, SwfdecFlvVideoTag, id);
476 if (keyframe) {
477 while (id > 0 && tag->frame_type != 1) {
478 id--;
479 tag--;
482 if (next_timestamp) {
483 if (id + 1 >= flv->video->len)
484 *next_timestamp = 0;
485 else
486 *next_timestamp = g_array_index (flv->video, SwfdecFlvVideoTag, id + 1).timestamp - offset;
488 if (real_timestamp)
489 *real_timestamp = tag->timestamp - offset;
490 if (format)
491 *format = tag->format;
492 return tag->buffer;
495 gboolean
496 swfdec_flv_decoder_get_video_info (SwfdecFlvDecoder *flv,
497 guint *first_timestamp, guint *last_timestamp)
499 g_return_val_if_fail (SWFDEC_IS_FLV_DECODER (flv), FALSE);
501 if (flv->video == NULL)
502 return FALSE;
504 if (flv->video->len == 0) {
505 if (first_timestamp)
506 *first_timestamp = 0;
507 if (last_timestamp)
508 *last_timestamp = 0;
509 return TRUE;
511 if (first_timestamp)
512 *first_timestamp = g_array_index (flv->video, SwfdecFlvVideoTag, 0).timestamp;
513 if (last_timestamp)
514 *last_timestamp = g_array_index (flv->video, SwfdecFlvVideoTag, flv->video->len - 1).timestamp;
515 return TRUE;
518 SwfdecBuffer *
519 swfdec_flv_decoder_get_audio (SwfdecFlvDecoder *flv, guint timestamp,
520 guint *codec, SwfdecAudioFormat *format,
521 guint *real_timestamp, guint *next_timestamp)
523 guint id, offset;
524 SwfdecFlvAudioTag *tag;
526 g_return_val_if_fail (SWFDEC_IS_FLV_DECODER (flv), NULL);
527 g_return_val_if_fail (flv->audio != NULL, NULL);
529 if (flv->audio->len == 0) {
530 if (next_timestamp)
531 *next_timestamp = 0;
532 if (real_timestamp)
533 *real_timestamp = 0;
534 if (codec)
535 *codec = SWFDEC_AUDIO_CODEC_UNDEFINED;
536 if (format)
537 *format = swfdec_audio_format_new (44100, 2, TRUE);
538 return NULL;
540 offset = g_array_index (flv->audio, SwfdecFlvAudioTag, 0).timestamp;
541 timestamp += offset;
542 id = swfdec_flv_decoder_find_audio (flv, timestamp);
543 if (next_timestamp) {
544 if (id + 1 >= flv->audio->len)
545 *next_timestamp = 0;
546 else
547 *next_timestamp = g_array_index (flv->audio, SwfdecFlvAudioTag, id + 1).timestamp - offset;
549 tag = &g_array_index (flv->audio, SwfdecFlvAudioTag, id);
550 if (real_timestamp)
551 *real_timestamp = tag->timestamp - offset;
552 if (codec)
553 *codec = tag->format;
554 if (format)
555 *format = tag->original_format;
556 return tag->buffer;
560 * swfdec_flv_decoder_get_data:
561 * @flv: a #SwfdecFlvDecoder
562 * @timestamp: timestamp to look for
563 * @real_timestamp: the timestamp of the returned buffer, if any
565 * Finds the next data event with a timestamp of at least @timestamp. If one
566 * exists, it is returned, and its real timestamp put into @real_timestamp.
567 * Otherwise, %NULL is returned.
569 * Returns: a #SwfdecBuffer containing the next data or NULL if none
571 SwfdecBuffer *
572 swfdec_flv_decoder_get_data (SwfdecFlvDecoder *flv, guint timestamp, guint *real_timestamp)
574 guint id;
575 SwfdecFlvDataTag *tag;
577 g_return_val_if_fail (SWFDEC_IS_FLV_DECODER (flv), NULL);
579 if (flv->data == NULL ||
580 flv->data->len == 0)
581 return NULL;
583 id = swfdec_flv_decoder_find_data (flv, timestamp);
584 tag = &g_array_index (flv->data, SwfdecFlvDataTag, id);
585 while (tag->timestamp < timestamp) {
586 id++;
587 if (id >= flv->data->len)
588 return NULL;
589 tag++;
591 if (real_timestamp)
592 *real_timestamp = tag->timestamp;
593 return tag->buffer;
596 gboolean
597 swfdec_flv_decoder_is_eof (SwfdecFlvDecoder *flv)
599 g_return_val_if_fail (SWFDEC_IS_FLV_DECODER (flv), TRUE);
601 return flv->state == SWFDEC_STATE_EOF;