📄 swfdec_net_stream.c
字号:
/* 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 <math.h>#include "swfdec_net_stream.h"#include "swfdec_amf.h"#include "swfdec_as_strings.h"#include "swfdec_audio_flv.h"#include "swfdec_debug.h"#include "swfdec_loader_internal.h"#include "swfdec_loadertarget.h"/* NB: code and level must be rooted gc-strings */static voidswfdec_net_stream_onstatus (SwfdecNetStream *stream, const char *code, const char *level){ SwfdecAsValue val; SwfdecAsObject *object; object = swfdec_as_object_new (SWFDEC_AS_OBJECT (stream)->context); if (!object) return; SWFDEC_INFO ("emitting onStatus for %s %s", level, code); SWFDEC_AS_VALUE_SET_STRING (&val, code); swfdec_as_object_set_variable (object, SWFDEC_AS_STR_code, &val); SWFDEC_AS_VALUE_SET_STRING (&val, level); swfdec_as_object_set_variable (object, SWFDEC_AS_STR_level, &val); SWFDEC_AS_VALUE_SET_OBJECT (&val, object); swfdec_as_object_call (SWFDEC_AS_OBJECT (stream), SWFDEC_AS_STR_onStatus, 1, &val, NULL);}static void swfdec_net_stream_update_playing (SwfdecNetStream *stream);static voidswfdec_net_stream_video_goto (SwfdecNetStream *stream, guint timestamp){ SwfdecBuffer *buffer; SwfdecVideoFormat format; cairo_surface_t *old; gboolean process_events; guint process_events_from; SWFDEC_LOG ("goto %ums", timestamp); process_events = timestamp == stream->next_time; process_events_from = MIN (stream->next_time, stream->current_time + 1); old = stream->surface; if (stream->surface) { cairo_surface_destroy (stream->surface); stream->surface = NULL; } if (stream->flvdecoder->video) { buffer = swfdec_flv_decoder_get_video (stream->flvdecoder, timestamp, FALSE, &format, &stream->current_time, &stream->next_time); } else { buffer = NULL; } if (buffer == NULL) { SWFDEC_ERROR ("got no buffer - no video available?"); } else { if (format != stream->format) { if (stream->decoder) swfdec_video_decoder_free (stream->decoder); stream->format = format; stream->decoder = swfdec_video_decoder_new (format); } if (stream->decoder) { stream->surface = swfdec_video_decoder_decode (stream->decoder, buffer); } if (stream->surface) { GList *walk; for (walk = stream->movies; walk; walk = walk->next) { swfdec_video_movie_new_image (walk->data, stream->surface); } } } if (stream->next_time <= stream->current_time) { if (swfdec_flv_decoder_is_eof (stream->flvdecoder)) { swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Play_Stop, SWFDEC_AS_STR_status); } else { stream->buffering = TRUE; swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Empty, SWFDEC_AS_STR_status); } swfdec_net_stream_update_playing (stream); } if (process_events) { while (process_events_from <= stream->current_time) { SwfdecAsValue name, value; SwfdecBits bits; SwfdecBuffer *event = swfdec_flv_decoder_get_data (stream->flvdecoder, process_events_from, &process_events_from); if (!event) break; SWFDEC_LOG ("processing event from timestamp %u", process_events_from); process_events_from++; /* increase so we get the next event next time */ swfdec_bits_init (&bits, event); if (swfdec_amf_parse (SWFDEC_AS_OBJECT (stream)->context, &bits, 2, SWFDEC_AMF_STRING, &name, SWFDEC_AMF_MIXED_ARRAY, &value) != 2) { SWFDEC_ERROR ("could not parse data tag"); } else { swfdec_as_object_call (SWFDEC_AS_OBJECT (stream), SWFDEC_AS_VALUE_GET_STRING (&name), 1, &value, NULL); } } }}static voidswfdec_net_stream_timeout (SwfdecTimeout *timeout){ SwfdecNetStream *stream = SWFDEC_NET_STREAM ((guchar *) timeout - G_STRUCT_OFFSET (SwfdecNetStream, timeout)); SWFDEC_LOG ("timeout fired"); stream->timeout.callback = NULL; swfdec_net_stream_video_goto (stream, stream->next_time); if (stream->next_time > stream->current_time) { SWFDEC_LOG ("readding timeout"); stream->timeout.timestamp += SWFDEC_MSECS_TO_TICKS (stream->next_time - stream->current_time); stream->timeout.callback = swfdec_net_stream_timeout; swfdec_player_add_timeout (SWFDEC_PLAYER (SWFDEC_AS_OBJECT (stream)->context), &stream->timeout); } else { if (stream->audio) { /* FIXME: just unref and let it take care of removing itself? */ SWFDEC_LOG ("stopping audio due to EOS"); swfdec_audio_remove (stream->audio); g_object_unref (stream->audio); stream->audio = NULL; } }}static voidswfdec_net_stream_update_playing (SwfdecNetStream *stream){ SwfdecPlayer *player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (stream)->context); gboolean should_play; should_play = stream->playing; /* checks user-set play/pause */ should_play &= !stream->buffering; /* checks enough data is available */ should_play &= stream->flvdecoder != NULL; /* checks there even is something to play */ should_play &= stream->next_time > stream->current_time; /* checks if EOF */ if (should_play && stream->timeout.callback == NULL) { SWFDEC_DEBUG ("starting playback"); stream->timeout.callback = swfdec_net_stream_timeout; stream->timeout.timestamp = player->time + SWFDEC_MSECS_TO_TICKS (stream->next_time - stream->current_time); swfdec_player_add_timeout (player, &stream->timeout); if (stream->flvdecoder->audio) { g_assert (stream->audio == NULL); SWFDEC_LOG ("starting audio"); stream->audio = swfdec_audio_flv_new (player, stream->flvdecoder, stream->current_time); } else { SWFDEC_LOG ("no audio"); } } else if (!should_play && stream->timeout.callback != NULL) { if (stream->audio) { SWFDEC_LOG ("stopping audio"); swfdec_audio_remove (stream->audio); g_object_unref (stream->audio); stream->audio = NULL; } swfdec_player_remove_timeout (player, &stream->timeout); stream->timeout.callback = NULL; SWFDEC_DEBUG ("stopping playback"); }}/*** SWFDEC_LOADER_TARGET interface ***/static SwfdecPlayer *swfdec_net_stream_loader_target_get_player (SwfdecLoaderTarget *target){ return SWFDEC_PLAYER (SWFDEC_AS_OBJECT (target)->context);}static voidswfdec_net_stream_loader_target_error (SwfdecLoaderTarget *target, SwfdecLoader *loader){ SwfdecNetStream *stream = SWFDEC_NET_STREAM (target); if (stream->flvdecoder == NULL) swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Play_StreamNotFound, SWFDEC_AS_STR_error);}static voidswfdec_net_stream_loader_target_recheck (SwfdecNetStream *stream){ if (stream->buffering) { guint first, last; if (swfdec_flv_decoder_get_video_info (stream->flvdecoder, &first, &last)) { guint current = MAX (first, stream->current_time); if (current + stream->buffer_time <= last) { swfdec_net_stream_video_goto (stream, current); stream->buffering = FALSE; swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Buffer_Full, SWFDEC_AS_STR_status); } } else { SWFDEC_ERROR ("no video stream, how do we update buffering?"); } } swfdec_net_stream_update_playing (stream);}static voidswfdec_net_stream_loader_target_parse (SwfdecLoaderTarget *target, SwfdecLoader *loader){ SwfdecNetStream *stream = SWFDEC_NET_STREAM (target); SwfdecDecoderClass *klass; gboolean recheck = FALSE; if (loader->state != SWFDEC_LOADER_STATE_EOF && swfdec_buffer_queue_get_depth (loader->queue) == 0) { SWFDEC_INFO ("nothing to do"); return; } if (stream->flvdecoder == NULL) { /* FIXME: add mp3 support */ stream->flvdecoder = g_object_new (SWFDEC_TYPE_FLV_DECODER, NULL); SWFDEC_DECODER (stream->flvdecoder)->player = SWFDEC_PLAYER (SWFDEC_AS_OBJECT (stream)->context); SWFDEC_DECODER (stream->flvdecoder)->queue = loader->queue; swfdec_net_stream_onstatus (stream, SWFDEC_AS_STR_NetStream_Play_Start, SWFDEC_AS_STR_status); swfdec_loader_set_data_type (loader, SWFDEC_LOADER_DATA_FLV); } klass = SWFDEC_DECODER_GET_CLASS (stream->flvdecoder); g_return_if_fail (klass->parse); while (TRUE) { SwfdecStatus status = klass->parse (SWFDEC_DECODER (stream->flvdecoder)); switch (status) { case SWFDEC_STATUS_OK: break; case SWFDEC_STATUS_INIT: /* HACK for native flv playback */ swfdec_player_initialize (SWFDEC_PLAYER (SWFDEC_AS_OBJECT (stream)->context), 7, SWFDEC_DECODER (stream->flvdecoder)->rate, SWFDEC_DECODER (stream->flvdecoder)->width, SWFDEC_DECODER (stream->flvdecoder)->height); case SWFDEC_STATUS_IMAGE: recheck = TRUE; break; case SWFDEC_STATUS_ERROR: case SWFDEC_STATUS_NEEDBITS: case SWFDEC_STATUS_EOF: goto out; default: g_assert_not_reached (); return; } }out: if (recheck) swfdec_net_stream_loader_target_recheck (stream);}static voidswfdec_net_stream_loader_target_eof (SwfdecLoaderTarget *target, SwfdecLoader *loader){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -