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.
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
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"
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
)
65 swfdec_flv_decoder_dispose (GObject
*object
)
67 SwfdecFlvDecoder
*flv
= SWFDEC_FLV_DECODER (object
);
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
);
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
);
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
);
94 swfdec_buffer_queue_unref (flv
->queue
);
97 G_OBJECT_CLASS (swfdec_flv_decoder_parent_class
)->dispose (object
);
101 swfdec_flv_decoder_parse_header (SwfdecFlvDecoder
*flv
)
103 SwfdecBuffer
*buffer
;
105 guint version
, header_length
;
106 gboolean has_audio
, has_video
;
108 buffer
= swfdec_buffer_queue_peek (flv
->queue
, 9);
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
);
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
;
143 flv
->audio
= g_array_new (FALSE
, FALSE
, sizeof (SwfdecFlvAudioTag
));
146 flv
->video
= g_array_new (FALSE
, FALSE
, sizeof (SwfdecFlvVideoTag
));
148 flv
->state
= SWFDEC_STATE_LAST_TAG
;
150 return SWFDEC_STATUS_OK
;
154 swfdec_flv_decoder_parse_last_tag (SwfdecFlvDecoder
*flv
)
156 SwfdecBuffer
*buffer
;
160 buffer
= swfdec_buffer_queue_pull (flv
->queue
, 4);
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
;
173 swfdec_flv_decoder_find_video (SwfdecFlvDecoder
*flv
, guint timestamp
)
177 g_assert (flv
->video
);
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
) {
194 swfdec_flv_decoder_find_audio (SwfdecFlvDecoder
*flv
, guint timestamp
)
198 g_assert (flv
->audio
);
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
) {
215 swfdec_flv_decoder_find_data (SwfdecFlvDecoder
*flv
, guint timestamp
)
219 g_assert (flv
->data
);
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
) {
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
);
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
,
268 idx
= swfdec_flv_decoder_find_video (flv
, tag
.timestamp
);
269 g_array_insert_val (flv
->video
, idx
, tag
);
271 return SWFDEC_STATUS_IMAGE
;
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
);
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
,
307 idx
= swfdec_flv_decoder_find_audio (flv
, tag
.timestamp
);
308 g_array_insert_val (flv
->audio
, idx
, tag
);
310 return SWFDEC_STATUS_OK
;
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");
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
);
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
,
338 idx
= swfdec_flv_decoder_find_data (flv
, tag
.timestamp
);
339 g_array_insert_val (flv
->data
, idx
, tag
);
344 swfdec_flv_decoder_parse_tag (SwfdecFlvDecoder
*flv
)
346 SwfdecBuffer
*buffer
;
348 guint size
, type
, timestamp
;
349 SwfdecStatus ret
= SWFDEC_STATUS_OK
;
351 buffer
= swfdec_buffer_queue_peek (flv
->queue
, 4);
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
);
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
);
375 ret
= swfdec_flv_decoder_parse_audio_tag (flv
, &bits
, timestamp
);
378 ret
= swfdec_flv_decoder_parse_video_tag (flv
, &bits
, timestamp
);
381 swfdec_flv_decoder_parse_data_tag (flv
, &bits
, timestamp
);
384 SWFDEC_WARNING ("unknown tag (type %u)", type
);
387 swfdec_buffer_unref (buffer
);
388 flv
->state
= SWFDEC_STATE_LAST_TAG
;
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
);
401 switch (flv
->state
) {
402 case SWFDEC_STATE_HEADER
:
403 status
|= swfdec_flv_decoder_parse_header (flv
);
405 case SWFDEC_STATE_LAST_TAG
:
406 status
|= swfdec_flv_decoder_parse_last_tag (flv
);
408 case SWFDEC_STATE_TAG
:
409 status
|= swfdec_flv_decoder_parse_tag (flv
);
411 case SWFDEC_STATE_EOF
:
412 status
|= SWFDEC_STATUS_EOF
;
415 g_assert_not_reached ();
416 status
|= SWFDEC_STATUS_ERROR
;
419 } while ((status
& (SWFDEC_STATUS_EOF
| SWFDEC_STATUS_NEEDBITS
| SWFDEC_STATUS_ERROR
)) == 0);
425 swfdec_flv_decoder_eof (SwfdecDecoder
*dec
)
427 SwfdecFlvDecoder
*flv
= SWFDEC_FLV_DECODER (dec
);
429 flv
->state
= SWFDEC_STATE_EOF
;
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
;
447 swfdec_flv_decoder_init (SwfdecFlvDecoder
*flv
)
449 flv
->state
= SWFDEC_STATE_HEADER
;
450 flv
->queue
= swfdec_buffer_queue_new ();
454 swfdec_flv_decoder_get_video (SwfdecFlvDecoder
*flv
, guint timestamp
,
455 gboolean keyframe
, guint
*format
, guint
*real_timestamp
, guint
*next_timestamp
)
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) {
469 *format
= SWFDEC_VIDEO_CODEC_UNDEFINED
;
472 offset
= g_array_index (flv
->video
, SwfdecFlvVideoTag
, 0).timestamp
;
474 id
= swfdec_flv_decoder_find_video (flv
, timestamp
);
475 tag
= &g_array_index (flv
->video
, SwfdecFlvVideoTag
, id
);
477 while (id
> 0 && tag
->frame_type
!= 1) {
482 if (next_timestamp
) {
483 if (id
+ 1 >= flv
->video
->len
)
486 *next_timestamp
= g_array_index (flv
->video
, SwfdecFlvVideoTag
, id
+ 1).timestamp
- offset
;
489 *real_timestamp
= tag
->timestamp
- offset
;
491 *format
= tag
->format
;
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
)
504 if (flv
->video
->len
== 0) {
506 *first_timestamp
= 0;
512 *first_timestamp
= g_array_index (flv
->video
, SwfdecFlvVideoTag
, 0).timestamp
;
514 *last_timestamp
= g_array_index (flv
->video
, SwfdecFlvVideoTag
, flv
->video
->len
- 1).timestamp
;
519 swfdec_flv_decoder_get_audio (SwfdecFlvDecoder
*flv
, guint timestamp
,
520 guint
*codec
, SwfdecAudioFormat
*format
,
521 guint
*real_timestamp
, guint
*next_timestamp
)
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) {
535 *codec
= SWFDEC_AUDIO_CODEC_UNDEFINED
;
537 *format
= swfdec_audio_format_new (44100, 2, TRUE
);
540 offset
= g_array_index (flv
->audio
, SwfdecFlvAudioTag
, 0).timestamp
;
542 id
= swfdec_flv_decoder_find_audio (flv
, timestamp
);
543 if (next_timestamp
) {
544 if (id
+ 1 >= flv
->audio
->len
)
547 *next_timestamp
= g_array_index (flv
->audio
, SwfdecFlvAudioTag
, id
+ 1).timestamp
- offset
;
549 tag
= &g_array_index (flv
->audio
, SwfdecFlvAudioTag
, id
);
551 *real_timestamp
= tag
->timestamp
- offset
;
553 *codec
= tag
->format
;
555 *format
= tag
->original_format
;
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
572 swfdec_flv_decoder_get_data (SwfdecFlvDecoder
*flv
, guint timestamp
, guint
*real_timestamp
)
575 SwfdecFlvDataTag
*tag
;
577 g_return_val_if_fail (SWFDEC_IS_FLV_DECODER (flv
), NULL
);
579 if (flv
->data
== NULL
||
583 id
= swfdec_flv_decoder_find_data (flv
, timestamp
);
584 tag
= &g_array_index (flv
->data
, SwfdecFlvDataTag
, id
);
585 while (tag
->timestamp
< timestamp
) {
587 if (id
>= flv
->data
->len
)
592 *real_timestamp
= tag
->timestamp
;
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
;