rework video handling
[swfdec.git] / libswfdec / swfdec_codec_ffmpeg.c
blob9f5d872fa32b2a2360309634bc74e4adfcb04c28
1 /* Swfdec
2 * Copyright (C) 2006 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
23 #include <string.h>
24 #include <avcodec.h>
25 #include <swscale.h>
27 #include "swfdec_codec_audio.h"
28 #include "swfdec_codec_video.h"
29 #include "swfdec_debug.h"
30 #include "swfdec_internal.h"
32 /*** GENERAL ***/
34 static AVCodecContext *
35 swfdec_codec_ffmpeg_init (enum CodecID id)
37 AVCodec *codec;
38 AVCodecContext *ctx;
39 static gboolean initialized = FALSE;
41 if (!initialized) {
42 avcodec_init();
43 avcodec_register_all ();
44 initialized = TRUE;
47 codec = avcodec_find_decoder (id);
48 if (!codec)
49 return NULL;
51 ctx = avcodec_alloc_context ();
52 if (avcodec_open (ctx, codec) < 0)
53 goto fail;
55 return ctx;
56 fail:
57 SWFDEC_ERROR ("failed to initialize playback via ffmpeg");
58 avcodec_close (ctx);
59 av_free (ctx);
60 return NULL;
63 /*** AUDIO ***/
65 typedef struct {
66 SwfdecAudioDecoder decoder;
67 AVCodecContext * ctx;
68 SwfdecBufferQueue * queue;
69 } SwfdecAudioDecoderFFMpeg;
71 static SwfdecBuffer *
72 swfdec_codec_ffmpeg_convert (AVCodecContext *ctx, SwfdecBuffer *buffer)
74 SwfdecBuffer *ret;
75 guint count, i, j, rate;
76 gint16 *out, *in;
78 /* do the common case fast */
79 if (ctx->channels == 2 && ctx->sample_rate == 44100) {
80 ret = swfdec_buffer_new_and_alloc (buffer->length);
81 memcpy (ret->data, buffer->data, buffer->length);
82 return ret;
85 switch (ctx->sample_rate) {
86 case 44100:
87 rate = 1;
88 break;
89 case 22050:
90 rate = 2;
91 break;
92 case 11025:
93 rate = 4;
94 break;
95 default:
96 SWFDEC_ERROR ("unsupported sample rate %u", ctx->sample_rate);
97 return NULL;
99 if (ctx->channels == 1)
100 rate *= 2;
101 ret = swfdec_buffer_new_and_alloc (buffer->length * rate);
102 out = (gint16 *) ret->data;
103 in = (gint16 *) buffer->data;
104 count = buffer->length / 2;
106 for (i = 0; i < count; i++) {
107 for (j = 0; j < rate; j++) {
108 *out++ = *in;
110 in++;
112 return ret;
115 static void
116 swfdec_audio_decoder_ffmpeg_push (SwfdecAudioDecoder *dec, SwfdecBuffer *buffer)
118 SwfdecAudioDecoderFFMpeg *ffmpeg = (SwfdecAudioDecoderFFMpeg *) dec;
119 int out_size;
120 int len;
121 guint amount;
122 SwfdecBuffer *outbuf = NULL;
124 if (buffer == NULL)
125 return;
126 outbuf = swfdec_buffer_new_and_alloc (AVCODEC_MAX_AUDIO_FRAME_SIZE);
127 for (amount = 0; amount < buffer->length; amount += len) {
129 out_size = AVCODEC_MAX_AUDIO_FRAME_SIZE;
130 len = avcodec_decode_audio2 (ffmpeg->ctx, (short *) outbuf->data, &out_size, buffer->data + amount, buffer->length - amount);
132 if (len < 0) {
133 SWFDEC_ERROR ("Error %d while decoding", len);
134 swfdec_buffer_unref (outbuf);
135 return;
137 if (out_size > 0) {
138 SwfdecBuffer *convert;
139 outbuf->length = out_size;
140 convert = swfdec_codec_ffmpeg_convert (ffmpeg->ctx, outbuf);
141 if (convert == NULL) {
142 swfdec_buffer_unref (outbuf);
143 return;
145 swfdec_buffer_queue_push (ffmpeg->queue, convert);
146 outbuf->length = AVCODEC_MAX_AUDIO_FRAME_SIZE;
149 swfdec_buffer_unref (outbuf);
152 static SwfdecBuffer *
153 swfdec_audio_decoder_ffmpeg_pull (SwfdecAudioDecoder *dec)
155 SwfdecAudioDecoderFFMpeg *ffmpeg = (SwfdecAudioDecoderFFMpeg *) dec;
157 return swfdec_buffer_queue_pull_buffer (ffmpeg->queue);
160 static void
161 swfdec_audio_decoder_ffmpeg_free (SwfdecAudioDecoder *dec)
163 SwfdecAudioDecoderFFMpeg *ffmpeg = (SwfdecAudioDecoderFFMpeg *) dec;
165 avcodec_close (ffmpeg->ctx);
166 av_free (ffmpeg->ctx);
167 swfdec_buffer_queue_unref (ffmpeg->queue);
169 g_slice_free (SwfdecAudioDecoderFFMpeg, ffmpeg);
172 SwfdecAudioDecoder *
173 swfdec_audio_decoder_ffmpeg_new (SwfdecAudioCodec type, gboolean width, SwfdecAudioFormat format)
175 SwfdecAudioDecoderFFMpeg *ffmpeg;
176 AVCodecContext *ctx;
177 enum CodecID id;
179 switch (type) {
180 case SWFDEC_AUDIO_CODEC_ADPCM:
181 id = CODEC_ID_ADPCM_SWF;
182 break;
183 case SWFDEC_AUDIO_CODEC_MP3:
184 id = CODEC_ID_MP3;
185 break;
186 default:
187 return NULL;
189 ctx = swfdec_codec_ffmpeg_init (id);
190 if (ctx == NULL)
191 return NULL;
192 ffmpeg = g_slice_new (SwfdecAudioDecoderFFMpeg);
193 ffmpeg->ctx = ctx;
194 ffmpeg->queue = swfdec_buffer_queue_new ();
195 ffmpeg->decoder.out_format = SWFDEC_AUDIO_FORMAT_STEREO_44100;
196 ffmpeg->decoder.pull = swfdec_audio_decoder_ffmpeg_pull;
197 ffmpeg->decoder.push = swfdec_audio_decoder_ffmpeg_push;
198 ffmpeg->decoder.free = swfdec_audio_decoder_ffmpeg_free;
199 ctx->sample_rate = SWFDEC_AUDIO_FORMAT_RATE (format);
200 ctx->channels = SWFDEC_AUDIO_FORMAT_N_CHANNELS (format);
202 return &ffmpeg->decoder;
205 /*** VIDEO ***/
207 typedef struct {
208 SwfdecVideoDecoder decoder;
209 AVCodecContext * ctx; /* out context (d'oh) */
210 AVFrame * frame; /* the frame we use for decoding */
211 enum PixelFormat format; /* format we must output */
212 } SwfdecVideoDecoderFFMpeg;
214 static enum PixelFormat
215 swfdec_video_decoder_ffmpeg_get_format (SwfdecVideoCodec codec)
217 switch (swfdec_video_codec_get_format (codec)) {
218 case SWFDEC_VIDEO_FORMAT_RGBA:
219 return PIX_FMT_RGB32;
220 case SWFDEC_VIDEO_FORMAT_I420:
221 return PIX_FMT_YUV420P;
223 g_assert_not_reached ();
224 return PIX_FMT_RGB32;
227 #define ALIGNMENT 31
228 static gboolean
229 swfdec_video_decoder_ffmpeg_decode (SwfdecVideoDecoder *dec, SwfdecBuffer *buffer,
230 SwfdecVideoImage *image)
232 SwfdecVideoDecoderFFMpeg *codec = (SwfdecVideoDecoderFFMpeg *) dec;
233 int got_image = 0;
234 guchar *tmp, *aligned;
236 /* fullfill alignment and padding requirements */
237 tmp = g_try_malloc (buffer->length + ALIGNMENT + FF_INPUT_BUFFER_PADDING_SIZE);
238 if (tmp == NULL) {
239 SWFDEC_WARNING ("Could not allocate temporary memory");
240 return FALSE;
242 aligned = (guchar *) (((uintptr_t) tmp + ALIGNMENT) & ~ALIGNMENT);
243 memcpy (aligned, buffer->data, buffer->length);
244 memset (aligned + buffer->length, 0, FF_INPUT_BUFFER_PADDING_SIZE);
245 if (avcodec_decode_video (codec->ctx, codec->frame, &got_image,
246 aligned, buffer->length) < 0) {
247 g_free (tmp);
248 SWFDEC_WARNING ("error decoding frame");
249 return FALSE;
251 g_free (tmp);
252 if (got_image == 0) {
253 SWFDEC_WARNING ("did not get an image from decoding");
254 return FALSE;
256 if (codec->ctx->pix_fmt != codec->format) {
257 SWFDEC_WARNING ("decoded to wrong format, expected %u, but got %u",
258 codec->format, codec->ctx->pix_fmt);
259 return FALSE;
261 image->width = codec->ctx->width;
262 image->height = codec->ctx->height;
263 image->mask = NULL;
264 image->plane[0] = codec->frame->data[0];
265 image->plane[1] = codec->frame->data[1];
266 image->plane[2] = codec->frame->data[2];
267 image->rowstride[0] = codec->frame->linesize[0];
268 image->rowstride[1] = codec->frame->linesize[1];
269 image->rowstride[2] = codec->frame->linesize[2];
270 return TRUE;
273 static void
274 swfdec_video_decoder_ffmpeg_free (SwfdecVideoDecoder *dec)
276 SwfdecVideoDecoderFFMpeg *codec = (SwfdecVideoDecoderFFMpeg *) dec;
278 avcodec_close (codec->ctx);
279 av_free (codec->ctx);
280 av_free (codec->frame);
281 g_free (codec);
284 SwfdecVideoDecoder *
285 swfdec_video_decoder_ffmpeg_new (SwfdecVideoCodec type)
287 SwfdecVideoDecoderFFMpeg *codec;
288 AVCodecContext *ctx;
289 enum CodecID id;
291 switch (type) {
292 case SWFDEC_VIDEO_CODEC_H263:
293 id = CODEC_ID_FLV1;
294 break;
295 case SWFDEC_VIDEO_CODEC_SCREEN:
296 id = CODEC_ID_FLASHSV;
297 break;
298 case SWFDEC_VIDEO_CODEC_VP6:
299 id = CODEC_ID_VP6F;
300 break;
301 default:
302 return NULL;
304 ctx = swfdec_codec_ffmpeg_init (id);
306 if (ctx == NULL)
307 return NULL;
308 codec = g_new0 (SwfdecVideoDecoderFFMpeg, 1);
309 codec->decoder.decode = swfdec_video_decoder_ffmpeg_decode;
310 codec->decoder.free = swfdec_video_decoder_ffmpeg_free;
311 codec->ctx = ctx;
312 codec->frame = avcodec_alloc_frame ();
313 codec->format = swfdec_video_decoder_ffmpeg_get_format (type);
315 return &codec->decoder;
318 guint8 *
319 swfdec_video_ffmpeg_i420_to_rgb (SwfdecVideoImage *image)
321 struct SwsContext *sws;
322 AVPicture src, dst;
323 guint8 *data;
325 sws = sws_getContext (image->width, image->height, PIX_FMT_YUV420P,
326 image->width, image->height, PIX_FMT_RGB32, 0, NULL, NULL, NULL);
327 if (sws == NULL) {
328 SWFDEC_ERROR ("Could not get conversion context");
329 return NULL;
331 data = g_try_malloc (image->width * image->height * 4);
332 if (data == NULL) {
333 SWFDEC_ERROR ("Out of memory");
334 sws_freeContext (sws);
335 return NULL;
337 src.data[0] = (unsigned char *) image->plane[0];
338 src.data[1] = (unsigned char *) image->plane[1];
339 src.data[2] = (unsigned char *) image->plane[2];
340 src.data[3] = NULL;
341 src.linesize[0] = image->rowstride[0];
342 src.linesize[1] = image->rowstride[1];
343 src.linesize[2] = image->rowstride[2];
344 src.linesize[3] = 0;
345 avpicture_fill (&dst, data, PIX_FMT_RGB32, image->width, image->height);
346 sws_scale (sws, src.data, src.linesize, 0, image->height,
347 dst.data, dst.linesize);
348 sws_freeContext (sws);
349 return data;