⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 swfdec_flv_decoder.c

📁 Swfdec is a decoder/renderer for Macromedia Flash animations. The decoding and rendering engine is
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Swfdec * Copyright (C) 2007 Benjamin Otte <otte@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. *  * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. *  * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor,  * Boston, MA  02110-1301  USA */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include "swfdec_flv_decoder.h"#include "swfdec_audio_internal.h"#include "swfdec_bits.h"#include "swfdec_debug.h"enum {  SWFDEC_STATE_HEADER,			/* need to parse header */  SWFDEC_STATE_LAST_TAG,		/* read size of last tag */  SWFDEC_STATE_TAG,			/* read next tag */  SWFDEC_STATE_EOF			/* file is complete */};typedef struct _SwfdecFlvVideoTag SwfdecFlvVideoTag;typedef struct _SwfdecFlvAudioTag SwfdecFlvAudioTag;typedef struct _SwfdecFlvDataTag SwfdecFlvDataTag;struct _SwfdecFlvVideoTag {  guint			timestamp;		/* milliseconds */  SwfdecVideoFormat	format;			/* format in use */  int			frame_type;		/* 0: undefined, 1: keyframe, 2: iframe, 3: H263 disposable iframe */  SwfdecBuffer *	buffer;			/* buffer for this data */};struct _SwfdecFlvAudioTag {  guint			timestamp;		/* milliseconds */  SwfdecAudioFormat	format;			/* format in use */  gboolean		width;			/* TRUE for 16bit, FALSE for 8bit */  SwfdecAudioOut	original_format;      	/* channel/rate information */  SwfdecBuffer *	buffer;			/* buffer for this data */};struct _SwfdecFlvDataTag {  guint			timestamp;		/* milliseconds */  SwfdecBuffer *	buffer;			/* buffer containing raw AMF data */};G_DEFINE_TYPE (SwfdecFlvDecoder, swfdec_flv_decoder, SWFDEC_TYPE_DECODER)static voidswfdec_flv_decoder_dispose (GObject *object){  SwfdecFlvDecoder *flv = SWFDEC_FLV_DECODER (object);  guint i;  if (flv->audio) {    for (i = 0; i < flv->audio->len; i++) {      SwfdecFlvAudioTag *tag = &g_array_index (flv->audio, SwfdecFlvAudioTag, i);      swfdec_buffer_unref (tag->buffer);    }    g_array_free (flv->audio, TRUE);    flv->audio = NULL;  }  if (flv->video) {    for (i = 0; i < flv->video->len; i++) {      SwfdecFlvVideoTag *tag = &g_array_index (flv->video, SwfdecFlvVideoTag, i);      swfdec_buffer_unref (tag->buffer);    }    g_array_free (flv->video, TRUE);    flv->video = NULL;  }  if (flv->data) {    for (i = 0; i < flv->data->len; i++) {      SwfdecFlvDataTag *tag = &g_array_index (flv->data, SwfdecFlvDataTag, i);      swfdec_buffer_unref (tag->buffer);    }    g_array_free (flv->data, TRUE);    flv->data = NULL;  }  G_OBJECT_CLASS (swfdec_flv_decoder_parent_class)->dispose (object);}static SwfdecStatusswfdec_flv_decoder_parse_header (SwfdecFlvDecoder *flv){  SwfdecDecoder *dec = SWFDEC_DECODER (flv);  SwfdecBuffer *buffer;  SwfdecBits bits;  guint version, header_length;  gboolean has_audio, has_video;  /* NB: we're still reading from the original queue, since deflating is not initialized yet */  buffer = swfdec_buffer_queue_peek (dec->queue, 9);  if (buffer == NULL)    return SWFDEC_STATUS_NEEDBITS;  swfdec_bits_init (&bits, buffer);  /* Check if we're really an FLV file */  if (swfdec_bits_get_u8 (&bits) != 'F' ||      swfdec_bits_get_u8 (&bits) != 'L' ||      swfdec_bits_get_u8 (&bits) != 'V') {    swfdec_buffer_unref (buffer);    return SWFDEC_STATUS_ERROR;  }  version = swfdec_bits_get_u8 (&bits);  swfdec_bits_getbits (&bits, 5);  has_audio = swfdec_bits_getbit (&bits);  swfdec_bits_getbit (&bits);  has_video = swfdec_bits_getbit (&bits);  header_length = swfdec_bits_get_bu32 (&bits);  swfdec_buffer_unref (buffer);  if (header_length < 9) {    SWFDEC_ERROR ("invalid header length %u, must be 9 or greater", header_length);    /* FIXME: treat as error or ignore? */    return SWFDEC_STATUS_ERROR;  }  buffer = swfdec_buffer_queue_pull (dec->queue, header_length);  if (buffer == NULL)    return SWFDEC_STATUS_NEEDBITS;  swfdec_buffer_unref (buffer);  SWFDEC_LOG ("parsing flv stream");  SWFDEC_LOG (" version %u", version);  SWFDEC_LOG (" with%s audio", has_audio ? "" : "out");  SWFDEC_LOG (" with%s video", has_video ? "" : "out");  flv->version = version;  if (has_audio) {    flv->audio = g_array_new (FALSE, FALSE, sizeof (SwfdecFlvAudioTag));  }  if (has_video) {    flv->video = g_array_new (FALSE, FALSE, sizeof (SwfdecFlvVideoTag));  }  flv->state = SWFDEC_STATE_LAST_TAG;  return SWFDEC_STATUS_OK;}static SwfdecStatusswfdec_flv_decoder_parse_last_tag (SwfdecFlvDecoder *flv){  SwfdecDecoder *dec = SWFDEC_DECODER (flv);  SwfdecBuffer *buffer;  SwfdecBits bits;  guint last_tag;  buffer = swfdec_buffer_queue_pull (dec->queue, 4);  if (buffer == NULL)    return SWFDEC_STATUS_NEEDBITS;  swfdec_bits_init (&bits, buffer);  last_tag = swfdec_bits_get_bu32 (&bits);  SWFDEC_LOG ("last tag was %u bytes", last_tag);  swfdec_buffer_unref (buffer);  flv->state = SWFDEC_STATE_TAG;  return SWFDEC_STATUS_OK;}static guintswfdec_flv_decoder_find_video (SwfdecFlvDecoder *flv, guint timestamp){  guint min, max;  g_assert (flv->video);    min = 0;  max = flv->video->len;  while (max - min > 1) {    guint cur = (max + min) / 2;    SwfdecFlvVideoTag *tag = &g_array_index (flv->video, SwfdecFlvVideoTag, cur);    if (tag->timestamp > timestamp) {      max = cur;    } else {      min = cur;    }  }  return min;}static guintswfdec_flv_decoder_find_audio (SwfdecFlvDecoder *flv, guint timestamp){  guint min, max;  g_assert (flv->audio);    min = 0;  max = flv->audio->len;  while (max - min > 1) {    guint cur = (max + min) / 2;    SwfdecFlvAudioTag *tag = &g_array_index (flv->audio, SwfdecFlvAudioTag, cur);    if (tag->timestamp > timestamp) {      max = cur;    } else {      min = cur;    }  }  return min;}static guintswfdec_flv_decoder_find_data (SwfdecFlvDecoder *flv, guint timestamp){  guint min, max;  g_assert (flv->data);    min = 0;  max = flv->data->len;  while (max - min > 1) {    guint cur = (max + min) / 2;    SwfdecFlvDataTag *tag = &g_array_index (flv->data, SwfdecFlvDataTag, cur);    if (tag->timestamp > timestamp) {      max = cur;    } else {      min = cur;    }  }  return min;}static SwfdecStatusswfdec_flv_decoder_parse_video_tag (SwfdecFlvDecoder *flv, SwfdecBits *bits, guint timestamp){  SwfdecDecoder *dec = SWFDEC_DECODER (flv);  SwfdecFlvVideoTag tag;  if (flv->video == NULL) {    SWFDEC_ERROR ("wow, video tags in an FLV without video!");    return SWFDEC_STATUS_OK;  }  tag.timestamp = timestamp;  tag.frame_type = swfdec_bits_getbits (bits, 4);  tag.format = swfdec_bits_getbits (bits, 4);  tag.buffer = swfdec_bits_get_buffer (bits, -1);  SWFDEC_LOG ("  format: %u", tag.format);  SWFDEC_LOG ("  frame type: %u", tag.frame_type);  if (tag.buffer == NULL) {    SWFDEC_WARNING ("no buffer, ignoring");    return SWFDEC_STATUS_OK;  }  if (flv->video->len == 0) {    g_array_append_val (flv->video, tag);  } else if (g_array_index (flv->video, SwfdecFlvVideoTag, 	flv->video->len - 1).timestamp < tag.timestamp) {    g_array_append_val (flv->video, tag);  } else {    guint idx;    SWFDEC_WARNING ("timestamps of video buffers not increasing (last was %u, now %u)",	g_array_index (flv->video, SwfdecFlvVideoTag, flv->video->len - 1).timestamp, 	tag.timestamp);    idx = swfdec_flv_decoder_find_video (flv, tag.timestamp);    g_array_insert_val (flv->video, idx, tag);  }  if (dec->width == 0 && dec->height == 0) {    SwfdecFlvVideoTag *t = &g_array_index (flv->video, SwfdecFlvVideoTag, 0);    SwfdecVideoDecoder *decoder;    cairo_surface_t *surface;    /* nice hack... */    decoder = swfdec_video_decoder_new (t->format);    if (decoder == NULL)      return SWFDEC_STATUS_OK;    surface = swfdec_video_decoder_decode (decoder, t->buffer);    if (surface == NULL)      return SWFDEC_STATUS_OK;    dec->width = cairo_image_surface_get_width (surface);    dec->height = cairo_image_surface_get_height (surface);    swfdec_video_decoder_free (decoder);    cairo_surface_destroy (surface);    return SWFDEC_STATUS_INIT;  } else {    return SWFDEC_STATUS_IMAGE;  }}static voidswfdec_flv_decoder_parse_audio_tag (SwfdecFlvDecoder *flv, SwfdecBits *bits, guint timestamp){  SwfdecFlvAudioTag tag;  int rate;  gboolean stereo;  if (flv->audio == NULL) {    SWFDEC_ERROR ("wow, audio tags in an FLV without audio!");    return;  }  tag.timestamp = timestamp;  tag.format = swfdec_bits_getbits (bits, 4);  rate = 44100 / (1 << (3 - swfdec_bits_getbits (bits, 2)));  tag.width = swfdec_bits_getbit (bits);  stereo = swfdec_bits_getbit (bits);  tag.original_format = SWFDEC_AUDIO_OUT_GET (stereo ? 2 : 1, rate);  tag.buffer = swfdec_bits_get_buffer (bits, -1);  SWFDEC_LOG ("  format: %u", (guint) tag.format);  SWFDEC_LOG ("  rate: %d", rate);  SWFDEC_LOG ("  channels: %d", stereo ? 2 : 1);  if (tag.buffer == NULL) {    SWFDEC_WARNING ("no buffer, ignoring");    return;  }  if (flv->audio->len == 0) {    g_array_append_val (flv->audio, tag);  } else if (g_array_index (flv->audio, SwfdecFlvAudioTag, 	flv->audio->len - 1).timestamp < tag.timestamp) {    g_array_append_val (flv->audio, tag);  } else {    guint idx;    SWFDEC_WARNING ("timestamps of audio buffers not increasing (last was %u, now %u)",	g_array_index (flv->audio, SwfdecFlvAudioTag, flv->audio->len - 1).timestamp, 	tag.timestamp);    idx = swfdec_flv_decoder_find_audio (flv, tag.timestamp);    g_array_insert_val (flv->audio, idx, tag);  }}static voidswfdec_flv_decoder_parse_data_tag (SwfdecFlvDecoder *flv, SwfdecBits *bits, guint timestamp){  SwfdecFlvDataTag tag;  if (flv->data == NULL) {    flv->data = g_array_new (FALSE, FALSE, sizeof (SwfdecFlvDataTag));  }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -