oops, I shifted the wrong value.
[swfdec.git] / swfdec / swfdec_audio_flv.c
blob2a49ee6edc16f10fff59f628ba33f6f3f007b3b9
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 <string.h>
25 #include "swfdec_audio_flv.h"
26 #include "swfdec_debug.h"
27 #include "swfdec_sound.h"
30 G_DEFINE_TYPE (SwfdecAudioFlv, swfdec_audio_flv, SWFDEC_TYPE_AUDIO)
32 static void
33 swfdec_audio_flv_dispose (GObject *object)
35 SwfdecAudioFlv *flv = SWFDEC_AUDIO_FLV (object);
37 if (flv->decoder != NULL) {
38 g_object_unref (flv->decoder);
39 flv->decoder = NULL;
41 g_queue_foreach (flv->playback_queue, (GFunc) swfdec_buffer_unref, NULL);
42 g_queue_free (flv->playback_queue);
43 g_object_unref (flv->flvdecoder);
45 G_OBJECT_CLASS (swfdec_audio_flv_parent_class)->dispose (object);
48 static SwfdecBuffer *
49 swfdec_audio_flv_decode_one (SwfdecAudioFlv *flv)
51 SwfdecBuffer *buffer;
52 guint format;
53 SwfdecAudioFormat in;
54 guint now, soon;
56 if (g_queue_is_empty (flv->playback_queue)) {
57 /* sync */
58 guint last;
59 swfdec_flv_decoder_get_audio (flv->flvdecoder,
60 SWFDEC_TICKS_TO_MSECS (flv->timestamp),
61 NULL, NULL, &last, NULL);
62 flv->playback_skip = SWFDEC_TICKS_TO_SAMPLES (
63 flv->timestamp - SWFDEC_MSECS_TO_TICKS (last));
64 flv->next_timestamp = last;
65 SWFDEC_DEBUG ("syncing to %ums: next timestamp to decode is %ums, skipping %u samples",
66 (guint) SWFDEC_TICKS_TO_MSECS (flv->timestamp),
67 flv->next_timestamp, flv->playback_skip);
69 if (flv->decoder)
70 buffer = swfdec_audio_decoder_pull (flv->decoder);
71 else
72 buffer = NULL;
73 while (buffer == NULL) {
74 if (flv->decoder && flv->next_timestamp == 0)
75 return NULL;
76 buffer = swfdec_flv_decoder_get_audio (flv->flvdecoder, flv->next_timestamp,
77 &format, &in, &now, &soon);
79 if (flv->next_timestamp != now) {
80 /* FIXME: do sync on first frame here */
81 SWFDEC_WARNING ("FIXME: didn't get requested timestamp - still loading?");
83 /* FIXME FIXME FIXME: This avoids decoding the last frame forever, however it ensures sync */
84 if (soon == 0)
85 return NULL;
86 flv->next_timestamp = soon;
87 if (flv->in == 0) {
88 /* init */
89 if (flv->decoder) {
90 g_object_unref (flv->decoder);
91 flv->decoder = NULL;
93 flv->format = format;
94 flv->in = in;
95 flv->decoder = swfdec_audio_decoder_new (flv->format, flv->in);
96 if (flv->decoder == NULL)
97 return NULL;
98 } else if (format != flv->format ||
99 in != flv->in) {
100 SWFDEC_ERROR ("FIXME: format change not implemented");
101 return NULL;
102 } else if (flv->decoder == NULL) {
103 return NULL;
105 swfdec_audio_decoder_push (flv->decoder, buffer);
106 if (flv->next_timestamp == 0)
107 swfdec_audio_decoder_push (flv->decoder, NULL);
108 buffer = swfdec_audio_decoder_pull (flv->decoder);
111 g_queue_push_tail (flv->playback_queue, buffer);
112 return buffer;
115 static gsize
116 swfdec_audio_flv_render (SwfdecAudio *audio, gint16* dest,
117 gsize start, gsize n_samples)
119 SwfdecAudioFlv *flv = SWFDEC_AUDIO_FLV (audio);
120 GList *walk;
121 gsize samples, rendered;
122 SwfdecBuffer *buffer;
124 g_assert (start < G_MAXINT);
125 start += flv->playback_skip;
126 SWFDEC_LOG ("flv %p rendering offset %"G_GSIZE_FORMAT", samples %"G_GSIZE_FORMAT,
127 flv, start, n_samples);
128 walk = g_queue_peek_head_link (flv->playback_queue);
129 for (rendered = 0; rendered < n_samples;) {
130 if (walk) {
131 buffer = walk->data;
132 walk = walk->next;
133 } else {
134 buffer = swfdec_audio_flv_decode_one (flv);
135 if (!buffer)
136 break;
138 samples = swfdec_sound_buffer_get_n_samples (buffer,
139 swfdec_audio_format_new (44100, 2, TRUE));
140 if (start) {
141 if (samples <= start) {
142 start -= samples;
143 continue;
145 samples -= start;
146 SWFDEC_LOG ("rendering %"G_GSIZE_FORMAT" samples, skipping %"G_GSIZE_FORMAT,
147 samples, start);
148 } else {
149 SWFDEC_LOG ("rendering %"G_GSIZE_FORMAT" samples", samples);
151 samples = MIN (samples, n_samples - rendered);
152 swfdec_sound_buffer_render (dest, buffer, start, samples);
153 start = 0;
154 rendered += samples;
155 dest += 2 * samples;
157 return rendered;
160 static gsize
161 swfdec_audio_flv_iterate (SwfdecAudio *audio, gsize remove)
163 SwfdecAudioFlv *flv = SWFDEC_AUDIO_FLV (audio);
164 SwfdecBuffer *buffer;
165 guint next;
167 flv->playback_skip += remove;
168 buffer = g_queue_peek_head (flv->playback_queue);
169 while (buffer && flv->playback_skip >=
170 swfdec_sound_buffer_get_n_samples (buffer, swfdec_audio_format_new (44100, 2, TRUE))
171 + swfdec_audio_format_get_granularity (swfdec_audio_format_new (44100, 2, TRUE))) {
172 buffer = g_queue_pop_head (flv->playback_queue);
173 SWFDEC_LOG ("removing buffer with %u samples",
174 swfdec_sound_buffer_get_n_samples (buffer, swfdec_audio_format_new (44100, 2, TRUE)));
175 flv->playback_skip -= swfdec_sound_buffer_get_n_samples (buffer,
176 swfdec_audio_format_new (44100, 2, TRUE));
177 swfdec_buffer_unref (buffer);
178 buffer = g_queue_peek_head (flv->playback_queue);
180 flv->timestamp += SWFDEC_SAMPLES_TO_TICKS (remove);
182 if (!g_queue_is_empty (flv->playback_queue))
183 return G_MAXUINT;
184 swfdec_flv_decoder_get_audio (flv->flvdecoder,
185 SWFDEC_TICKS_TO_MSECS (flv->timestamp),
186 NULL, NULL, NULL, &next);
187 return next ? G_MAXUINT : 0;
190 static void
191 swfdec_audio_flv_class_init (SwfdecAudioFlvClass *klass)
193 GObjectClass *object_class = G_OBJECT_CLASS (klass);
194 SwfdecAudioClass *audio_class = SWFDEC_AUDIO_CLASS (klass);
196 object_class->dispose = swfdec_audio_flv_dispose;
198 audio_class->iterate = swfdec_audio_flv_iterate;
199 audio_class->render = swfdec_audio_flv_render;
202 static void
203 swfdec_audio_flv_init (SwfdecAudioFlv *flv)
205 flv->playback_queue = g_queue_new ();
208 SwfdecAudio *
209 swfdec_audio_flv_new (SwfdecPlayer *player, SwfdecFlvDecoder *decoder, guint timestamp)
211 SwfdecAudioFlv *flv;
213 flv = g_object_new (SWFDEC_TYPE_AUDIO_FLV, NULL);
215 SWFDEC_DEBUG ("new audio flv for decoder %p, starting at %ums",
216 decoder, timestamp);
217 g_object_ref (decoder);
218 flv->flvdecoder = decoder;
219 flv->timestamp = SWFDEC_MSECS_TO_TICKS (timestamp);
220 swfdec_audio_add (SWFDEC_AUDIO (flv), player);
222 return SWFDEC_AUDIO (flv);