/* Advance the SPU packet/command queue to a time. new_ts is in running time */ static void gst_dvd_spu_advance_spu (GstDVDSpu * dvdspu, GstClockTime new_ts) { SpuState *state = &dvdspu->spu_state; if (G_UNLIKELY (dvdspu->spu_input_type == SPU_INPUT_TYPE_NONE)) return; while (state->next_ts == GST_CLOCK_TIME_NONE || state->next_ts <= new_ts) { GST_DEBUG_OBJECT (dvdspu, "Advancing SPU from TS %" GST_TIME_FORMAT " to %" GST_TIME_FORMAT, GST_TIME_ARGS (state->next_ts), GST_TIME_ARGS (new_ts)); if (!gstspu_execute_event (dvdspu)) { GstClockTime vid_run_ts; /* No current command buffer, try and get one */ SpuPacket *packet = (SpuPacket *) g_queue_pop_head (dvdspu->pending_spus); if (packet == NULL) return; /* No SPU packets available */ vid_run_ts = gst_segment_to_running_time (&dvdspu->video_seg, GST_FORMAT_TIME, dvdspu->video_seg.position); GST_LOG_OBJECT (dvdspu, "Popped new SPU packet with TS %" GST_TIME_FORMAT ". Video position=%" GST_TIME_FORMAT " (%" GST_TIME_FORMAT ") type %s", GST_TIME_ARGS (packet->event_ts), GST_TIME_ARGS (vid_run_ts), GST_TIME_ARGS (dvdspu->video_seg.position), packet->buf ? "buffer" : "event"); if (packet->buf) { switch (dvdspu->spu_input_type) { case SPU_INPUT_TYPE_VOBSUB: gstspu_vobsub_handle_new_buf (dvdspu, packet->event_ts, packet->buf); break; case SPU_INPUT_TYPE_PGS: gstspu_pgs_handle_new_buf (dvdspu, packet->event_ts, packet->buf); break; default: g_assert_not_reached (); break; } g_assert (packet->event == NULL); } else if (packet->event) gst_dvd_spu_handle_dvd_event (dvdspu, packet->event); g_free (packet); continue; } } }
static gboolean gst_dvd_spu_subpic_event (GstPad * pad, GstObject * parent, GstEvent * event) { GstDVDSpu *dvdspu = (GstDVDSpu *) parent; gboolean res = TRUE; /* Some events on the subpicture sink pad just get ignored, like * FLUSH_START */ switch (GST_EVENT_TYPE (event)) { case GST_EVENT_CAPS: { GstCaps *caps; gst_event_parse_caps (event, &caps); res = gst_dvd_spu_subpic_set_caps (pad, caps); gst_event_unref (event); break; } case GST_EVENT_CUSTOM_DOWNSTREAM: case GST_EVENT_CUSTOM_DOWNSTREAM_STICKY: case GST_EVENT_CUSTOM_DOWNSTREAM_OOB: { const GstStructure *structure = gst_event_get_structure (event); gboolean need_push; if (!gst_structure_has_name (structure, "application/x-gst-dvd")) { res = gst_pad_event_default (pad, parent, event); break; } DVD_SPU_LOCK (dvdspu); if (GST_EVENT_IS_SERIALIZED (event)) { SpuPacket *spu_packet = g_new0 (SpuPacket, 1); GST_DEBUG_OBJECT (dvdspu, "Enqueueing DVD event on subpicture pad for later"); spu_packet->event = event; g_queue_push_tail (dvdspu->pending_spus, spu_packet); } else { gst_dvd_spu_handle_dvd_event (dvdspu, event); } /* If the handle_dvd_event generated a pending frame, we * need to synchronise with the video pad's stream lock and push it. * This requires some dancing to preserve locking order and handle * flushes correctly */ need_push = (dvdspu->pending_frame != NULL); DVD_SPU_UNLOCK (dvdspu); if (need_push) { GstBuffer *to_push = NULL; gboolean flushing; GST_LOG_OBJECT (dvdspu, "Going for stream lock"); GST_PAD_STREAM_LOCK (dvdspu->videosinkpad); GST_LOG_OBJECT (dvdspu, "Got stream lock"); GST_OBJECT_LOCK (dvdspu->videosinkpad); flushing = GST_PAD_IS_FLUSHING (dvdspu->videosinkpad); GST_OBJECT_UNLOCK (dvdspu->videosinkpad); DVD_SPU_LOCK (dvdspu); if (dvdspu->pending_frame == NULL || flushing) { /* Got flushed while waiting for the stream lock */ DVD_SPU_UNLOCK (dvdspu); } else { to_push = dvdspu->pending_frame; dvdspu->pending_frame = NULL; DVD_SPU_UNLOCK (dvdspu); gst_pad_push (dvdspu->srcpad, to_push); } GST_LOG_OBJECT (dvdspu, "Dropping stream lock"); GST_PAD_STREAM_UNLOCK (dvdspu->videosinkpad); } break; } case GST_EVENT_SEGMENT: { GstSegment seg; gst_event_copy_segment (event, &seg); /* Only print updates if they have an end time (don't print start_time * updates */ GST_DEBUG_OBJECT (dvdspu, "subpic pad Segment: %" GST_SEGMENT_FORMAT, &seg); DVD_SPU_LOCK (dvdspu); dvdspu->subp_seg = seg; GST_LOG_OBJECT (dvdspu, "Subpicture segment now: %" GST_SEGMENT_FORMAT, &dvdspu->subp_seg); DVD_SPU_UNLOCK (dvdspu); gst_event_unref (event); break; } case GST_EVENT_GAP: { GstClockTime timestamp, duration; gst_event_parse_gap (event, ×tamp, &duration); if (GST_CLOCK_TIME_IS_VALID (duration)) timestamp += duration; DVD_SPU_LOCK (dvdspu); dvdspu->subp_seg.position = timestamp; GST_LOG_OBJECT (dvdspu, "Received GAP. Segment now: %" GST_SEGMENT_FORMAT, &dvdspu->subp_seg); DVD_SPU_UNLOCK (dvdspu); gst_event_unref (event); break; } case GST_EVENT_FLUSH_START: gst_event_unref (event); goto done; case GST_EVENT_FLUSH_STOP: GST_DEBUG_OBJECT (dvdspu, "Have flush-stop event on SPU pad"); DVD_SPU_LOCK (dvdspu); gst_segment_init (&dvdspu->subp_seg, GST_FORMAT_UNDEFINED); gst_dvd_spu_flush_spu_info (dvdspu, TRUE); DVD_SPU_UNLOCK (dvdspu); /* We don't forward flushes on the spu pad */ gst_event_unref (event); goto done; case GST_EVENT_EOS: /* drop EOS on the subtitle pad, it means there are no more subtitles, * video might still continue, though */ gst_event_unref (event); goto done; break; default: res = gst_pad_event_default (pad, parent, event); break; } done: return res; }