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

📄 swfdec_playback.c

📁 Swfdec is a decoder/renderer for Macromedia Flash animations. The decoding and rendering engine is
💻 C
字号:
/* Swfdec * Copyright (C) 2006 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 <alsa/asoundlib.h>#include "swfdec_playback.h"/* Why ALSA sucks for beginners: * - snd_pcm_delay is not sample-exact, but period-exact most of the time. *   Yay for getting told the time every 512 samples when a human notices *   a delay of 100 samples (oooops) * - lots of functions are simply not implemented. So the super-smart idea *   of using snd_pcm_rewind to avoid XRUNS and still get low latency has *   some issues when dmix just returns -EIO all of the time. That wouldn't *   be so bad if there was actually a way to query if it's supported. * - But to make up for all this, you have 10 hardware parameters, 10  *   software parameters and 10 configuration parameters. All of this is *   naturally supported on 10 driver APIs depending on kernel. So if your *   sound card seems to do weird stuff, that is not my fault. * Welcome to Linux sound in the 21st century. *//*** DEFINITIONS ***/struct _SwfdecPlayback {  SwfdecPlayer *	player;  GList *		streams;	/* all Stream objects */  GMainContext *	context;	/* context we work in */};typedef struct {  SwfdecPlayback *     	sound;		/* reference to sound object */  SwfdecAudio *		audio;		/* the audio we play back */  snd_pcm_t *		pcm;		/* the pcm we play back to */  GSource **		sources;	/* sources for writing data */  guint			n_sources;	/* number of sources */  guint			offset;		/* offset into sound */} Stream;#define ALSA_TRY(func,msg) G_STMT_START{ \  int err = func; \  if (err < 0) \    g_printerr (msg ": %s\n", snd_strerror (err)); \}G_STMT_END#define ALSA_ERROR(func,msg,retval) G_STMT_START { \  int err = func; \  if (err < 0) { \    g_printerr (msg ": %s\n", snd_strerror (err)); \    return retval; \  } \}G_STMT_END/*** STREAMS ***/static snd_pcm_uframes_twrite_player (Stream *stream, const snd_pcm_channel_area_t *dst,     snd_pcm_uframes_t offset, snd_pcm_uframes_t avail){  /* FIXME: do a long path if this doesn't hold */  g_assert (dst[1].first - dst[0].first == 16);  g_assert (dst[0].addr == dst[1].addr);  g_assert (dst[0].step == dst[1].step);  g_assert (dst[0].step == 32);  memset ((guint8 *) dst[0].addr + offset * dst[0].step / 8, 0, avail * 4);  swfdec_audio_render (stream->audio, (gint16 *) ((guint8 *) dst[0].addr + offset * dst[0].step / 8),       stream->offset, avail);  //g_print ("rendering %u %u\n", stream->offset, (guint) avail);  return avail;}static gbooleantry_write (Stream *stream){  snd_pcm_sframes_t avail_result;  snd_pcm_uframes_t offset, avail;  const snd_pcm_channel_area_t *dst;  while (TRUE) {    avail_result = snd_pcm_avail_update (stream->pcm);    ALSA_ERROR (avail_result, "snd_pcm_avail_update failed", FALSE);    if (avail_result == 0)      return TRUE;    avail = avail_result;    ALSA_ERROR (snd_pcm_mmap_begin (stream->pcm, &dst, &offset, &avail),	"snd_pcm_mmap_begin failed", FALSE);    //g_print ("  avail = %u\n", (guint) avail);    avail = write_player (stream, dst, offset, avail);    if (snd_pcm_mmap_commit (stream->pcm, offset, avail) < 0) {      g_printerr ("snd_pcm_mmap_commit failed\n");      return FALSE;    }    stream->offset += avail;    //g_print ("offset: %u (+%u)\n", stream->offset, (guint) avail);  }  return TRUE;}static voidswfdec_stream_remove_handlers (Stream *stream){  guint i;  for (i = 0; i < stream->n_sources; i++) {    if (stream->sources[i]) {      g_source_destroy (stream->sources[i]);      g_source_unref (stream->sources[i]);      stream->sources[i] = NULL;    }  }}static void swfdec_stream_start (Stream *stream);static gbooleanhandle_stream (GIOChannel *source, GIOCondition cond, gpointer data){  Stream *stream = data;  snd_pcm_state_t state;  state = snd_pcm_state (stream->pcm);  if (state != SND_PCM_STATE_RUNNING) {    swfdec_stream_start (stream);  } else {    try_write (stream);  }  return TRUE;}static voidswfdec_stream_install_handlers (Stream *stream){  GIOChannel *channel;  if (stream->n_sources > 0) {    struct pollfd polls[stream->n_sources];    guint i, count;    if (stream->n_sources > 1)      g_printerr ("attention: more than one fd!\n");    count = snd_pcm_poll_descriptors (stream->pcm, polls, stream->n_sources);    for (i = 0; i < count; i++) {      if (stream->sources[i] != NULL)	continue;      channel = g_io_channel_unix_new (polls[i].fd);      stream->sources[i] = g_io_create_watch (channel, polls[i].events);      g_source_set_priority (stream->sources[i], G_PRIORITY_HIGH);      g_source_set_callback (stream->sources[i], (GSourceFunc) handle_stream, stream, NULL);      g_io_channel_unref (channel);      g_source_attach (stream->sources[i], stream->sound->context);    }  }}static voidswfdec_stream_start (Stream *stream){  snd_pcm_state_t state = snd_pcm_state (stream->pcm);  switch (state) {    case SND_PCM_STATE_XRUN:      ALSA_ERROR (snd_pcm_prepare (stream->pcm), "no prepare",);      //g_print ("XRUN!\n");      /* fall through */    case SND_PCM_STATE_SUSPENDED:    case SND_PCM_STATE_PREPARED:      stream->offset = 0;      //g_print ("offset: %u (delay: %ld)\n", sound->offset, delay);      if (try_write (stream)) {	ALSA_ERROR (snd_pcm_start (stream->pcm), "error starting",);	swfdec_stream_install_handlers (stream);      }      break;    default:      break;  }}static voidswfdec_stream_open (SwfdecPlayback *sound, SwfdecAudio *audio){  Stream *stream;  snd_pcm_t *ret;  snd_pcm_hw_params_t *hw_params;  guint rate;  snd_pcm_uframes_t uframes;  /* "default" uses dmix, and dmix ticks way slow, so this thingy here stutters */  ALSA_ERROR (snd_pcm_open (&ret, "default", SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK),      "Failed to open sound device", );  snd_pcm_hw_params_alloca (&hw_params);  if (snd_pcm_hw_params_any (ret, hw_params) < 0) {    g_printerr ("No sound format available\n");    return;  }  if (snd_pcm_hw_params_set_access (ret, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {    g_printerr ("Failed setting access\n");    goto fail;  }  if (snd_pcm_hw_params_set_format (ret, hw_params, SND_PCM_FORMAT_S16) < 0) {    g_printerr ("Failed setting format\n");    goto fail;  }  if (snd_pcm_hw_params_set_channels (ret, hw_params, 2) < 0) {    g_printerr ("Failed setting channels\n");    goto fail;  }  rate = 44100;  if (snd_pcm_hw_params_set_rate_near (ret, hw_params, &rate, 0) < 0) {    g_printerr ("Failed setting rate\n");    goto fail;  }  uframes = 16384;  if (snd_pcm_hw_params_set_buffer_size_near (ret, hw_params, &uframes) < 0) {    g_printerr ("Failed setting buffer size\n");    goto fail;  }  if (snd_pcm_hw_params (ret, hw_params) < 0) {    g_printerr ("Could not set hardware parameters\n");    goto fail;  }#if 0  {    snd_output_t *log;    snd_output_stdio_attach (&log, stderr, 0);    snd_pcm_hw_params_dump (hw_params, log);  }#endif  stream = g_new0 (Stream, 1);  stream->sound = sound;  stream->audio = g_object_ref (audio);  stream->pcm = ret;  stream->n_sources = snd_pcm_poll_descriptors_count (ret);  if (stream->n_sources > 0)    stream->sources = g_new0 (GSource *, stream->n_sources);  sound->streams = g_list_prepend (sound->streams, stream);  swfdec_stream_start (stream);  return;fail:  snd_pcm_close (ret);}static voidswfdec_stream_close (Stream *stream){  ALSA_TRY (snd_pcm_close (stream->pcm), "failed closing");  swfdec_stream_remove_handlers (stream);  g_free (stream->sources);  stream->sound->streams = g_list_remove (stream->sound->streams, stream);  g_object_unref (stream->audio);  g_free (stream);}/*** SOUND ***/static voidadvance_before (SwfdecPlayer *player, guint msecs, guint audio_samples, gpointer data){  SwfdecPlayback *sound = data;  GList *walk;  for (walk = sound->streams; walk; walk = walk->next) {    Stream *stream = walk->data;    if (audio_samples >= stream->offset) {      stream->offset = 0;    } else {      stream->offset -= audio_samples;    }  }}static voidaudio_added (SwfdecPlayer *player, SwfdecAudio *audio, SwfdecPlayback *sound){  swfdec_stream_open (sound, audio);}static voidaudio_removed (SwfdecPlayer *player, SwfdecAudio *audio, SwfdecPlayback *sound){  GList *walk;  for (walk = sound->streams; walk; walk = walk->next) {    Stream *stream = walk->data;    if (stream->audio == audio) {      swfdec_stream_close (stream);      return;    }  }}SwfdecPlayback *swfdec_playback_open (SwfdecPlayer *player, GMainContext *context){  SwfdecPlayback *sound;  const GList *walk;  g_return_val_if_fail (SWFDEC_IS_PLAYER (player), NULL);  g_return_val_if_fail (context != NULL, NULL);  sound = g_new0 (SwfdecPlayback, 1);  sound->player = player;  g_signal_connect (player, "advance", G_CALLBACK (advance_before), sound);  g_signal_connect (player, "audio-added", G_CALLBACK (audio_added), sound);  g_signal_connect (player, "audio-removed", G_CALLBACK (audio_removed), sound);  for (walk = swfdec_player_get_audio (player); walk; walk = walk->next) {    swfdec_stream_open (sound, walk->data);  }  g_main_context_ref (context);  sound->context = context;  return sound;}voidswfdec_playback_close (SwfdecPlayback *sound){#define REMOVE_HANDLER_FULL(obj,func,data,count) G_STMT_START {\  if (g_signal_handlers_disconnect_by_func ((obj), \	G_CALLBACK (func), (data)) != (count)) { \    g_assert_not_reached (); \  } \} G_STMT_END#define REMOVE_HANDLER(obj,func,data) REMOVE_HANDLER_FULL (obj, func, data, 1)  while (sound->streams)    swfdec_stream_close (sound->streams->data);  REMOVE_HANDLER (sound->player, advance_before, sound);  REMOVE_HANDLER (sound->player, audio_added, sound);  REMOVE_HANDLER (sound->player, audio_removed, sound);  g_main_context_unref (sound->context);  g_free (sound);}

⌨️ 快捷键说明

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