static gboolean do_seek (App * app) { gint64 in_pos, out_pos; gfloat rate = 1.0; GstFormat fmt = GST_FORMAT_TIME; GstSeekFlags flags = 0; int ret; if (app->current_segment >= app->segment_count) { GST_WARNING ("seek segment not found!"); return FALSE; } GST_INFO ("do_seek..."); flags |= GST_SEEK_FLAG_FLUSH; // flags |= GST_SEEK_FLAG_ACCURATE; flags |= GST_SEEK_FLAG_KEY_UNIT; flags |= GST_SEEK_FLAG_SEGMENT; gst_element_query_position ((app->pipeline), &fmt, &in_pos); GST_DEBUG ("do_seek::initial gst_element_query_position = %lld ms", in_pos / 1000000); in_pos = MPEGTIME_TO_GSTTIME (app->seek_segments[app->current_segment].in_pts); GST_DEBUG ("do_seek::in_time for segment %i = %lld ms", app->current_segment, in_pos / 1000000); out_pos = -1; // MPEGTIME_TO_GSTTIME (app->seek_segments[app->current_segment].out_pts); GST_DEBUG ("do_seek::out_time for segment %i = %lld ms", app->current_segment, out_pos / 1000000); ret = gst_element_seek ((app->pipeline), rate, GST_FORMAT_TIME, flags, GST_SEEK_TYPE_SET, in_pos, GST_SEEK_TYPE_SET, out_pos); gst_element_query_position ((app->pipeline), &fmt, &in_pos); GST_DEBUG ("do_seek::seek command returned %i. new gst_element_query_position = %lld ms", ret, in_pos / 1000000); if (ret) app->current_segment++; return ret; }
static GstFlowReturn gst_mpeg_demux_parse_pes (GstMPEGParse * mpeg_parse, GstBuffer * buffer) { GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (mpeg_parse); guint8 id; guint16 packet_length; guint8 header_data_length = 0; guint16 datalen; guint16 headerlen; GstClockTime timestamp; GstFlowReturn ret = GST_FLOW_OK; GstMPEGStream *outstream = NULL; guint8 *buf; buf = GST_BUFFER_DATA (buffer); id = *(buf + 3); buf += 4; /* start parsing */ packet_length = GST_READ_UINT16_BE (buf); GST_DEBUG_OBJECT (mpeg_demux, "packet_length %d", packet_length); buf += 2; /* we don't operate on: program_stream_map, padding_stream, */ /* private_stream_2, ECM, EMM, or program_stream_directory */ if ((id != 0xBC) && (id != 0xBE) && (id != 0xBF) && (id != 0xF0) && (id != 0xF1) && (id != 0xFF)) { guchar flags1 = *buf++; guchar flags2 = *buf++; if ((flags1 & 0xC0) != 0x80) { return FALSE; } header_data_length = *buf++; GST_DEBUG_OBJECT (mpeg_demux, "header_data_length: %d", header_data_length); /* check for PTS */ if ((flags2 & 0x80)) { gint64 pts; pts = ((guint64) (*buf++ & 0x0E)) << 29; pts |= ((guint64) * buf++) << 22; pts |= ((guint64) (*buf++ & 0xFE)) << 14; pts |= ((guint64) * buf++) << 7; pts |= ((guint64) (*buf++ & 0xFE)) >> 1; /* Check for pts overflow */ if (mpeg_demux->last_pts != -1) { gint32 diff = pts - mpeg_demux->last_pts; if (diff > -4 * CLOCK_FREQ && diff < 4 * CLOCK_FREQ) pts = mpeg_demux->last_pts + diff; } mpeg_demux->last_pts = pts; timestamp = PARSE_CLASS (mpeg_parse)->adjust_ts (mpeg_parse, MPEGTIME_TO_GSTTIME (pts)); GST_DEBUG_OBJECT (mpeg_demux, "0x%02x (% " G_GINT64_FORMAT ") PTS = %" G_GUINT64_FORMAT, id, pts, MPEGTIME_TO_GSTTIME (pts)); } else {
static GstFlowReturn gst_mpeg_demux_parse_packet (GstMPEGParse * mpeg_parse, GstBuffer * buffer) { GstMPEGDemux *mpeg_demux = GST_MPEG_DEMUX (mpeg_parse); guint8 id; guint16 headerlen; guint16 packet_length; gboolean STD_buffer_bound_scale; guint16 STD_buffer_size_bound; guint64 dts; gint64 pts = -1; guint16 datalen; GstMPEGStream *outstream = NULL; guint8 *buf, *basebuf; gint64 timestamp; GstFlowReturn ret = GST_FLOW_OK; basebuf = buf = GST_BUFFER_DATA (buffer); id = *(buf + 3); buf += 4; /* start parsing */ packet_length = GST_READ_UINT16_BE (buf); GST_DEBUG_OBJECT (mpeg_demux, "got packet_length %d", packet_length); headerlen = 2; buf += 2; /* loop through looping for stuffing bits, STD, PTS, DTS, etc */ do { guint8 bits = *buf++; /* stuffing bytes */ switch (bits & 0xC0) { case 0xC0: if (bits == 0xff) { GST_DEBUG_OBJECT (mpeg_demux, "have stuffing byte"); } else { GST_DEBUG_OBJECT (mpeg_demux, "expected stuffing byte"); } headerlen++; break; case 0x40: GST_DEBUG_OBJECT (mpeg_demux, "have STD"); STD_buffer_bound_scale = bits & 0x20; STD_buffer_size_bound = ((guint16) (bits & 0x1F)) << 8; STD_buffer_size_bound |= *buf++; headerlen += 2; break; case 0x00: switch (bits & 0x30) { case 0x20: /* pts:3 ! 1 ! pts:15 ! 1 | pts:15 ! 1 */ pts = ((guint64) (bits & 0x0E)) << 29; pts |= ((guint64) (*buf++)) << 22; pts |= ((guint64) (*buf++ & 0xFE)) << 14; pts |= ((guint64) (*buf++)) << 7; pts |= ((guint64) (*buf++ & 0xFE)) >> 1; GST_DEBUG_OBJECT (mpeg_demux, "PTS = %" G_GUINT64_FORMAT, pts); headerlen += 5; goto done; case 0x30: /* pts:3 ! 1 ! pts:15 ! 1 | pts:15 ! 1 */ pts = ((guint64) (bits & 0x0E)) << 29; pts |= ((guint64) (*buf++)) << 22; pts |= ((guint64) (*buf++ & 0xFE)) << 14; pts |= ((guint64) (*buf++)) << 7; pts |= ((guint64) (*buf++ & 0xFE)) >> 1; /* sync:4 ! pts:3 ! 1 ! pts:15 ! 1 | pts:15 ! 1 */ dts = ((guint64) (*buf++ & 0x0E)) << 29; dts |= ((guint64) * buf++) << 22; dts |= ((guint64) (*buf++ & 0xFE)) << 14; dts |= ((guint64) * buf++) << 7; dts |= ((guint64) (*buf++ & 0xFE)) >> 1; GST_DEBUG_OBJECT (mpeg_demux, "PTS = %" G_GUINT64_FORMAT ", DTS = %" G_GUINT64_FORMAT, pts, dts); headerlen += 10; goto done; case 0x00: GST_DEBUG_OBJECT (mpeg_demux, "have no pts/dts"); GST_DEBUG_OBJECT (mpeg_demux, "got trailer bits %x", (bits & 0x0f)); if ((bits & 0x0f) != 0xf) { GST_DEBUG_OBJECT (mpeg_demux, "not a valid packet time sequence"); return FALSE; } headerlen++; default: goto done; } default: goto done; } } while (1); GST_DEBUG_OBJECT (mpeg_demux, "done with header loop"); done: /* calculate the amount of real data in this packet */ datalen = packet_length - headerlen + 2; GST_DEBUG_OBJECT (mpeg_demux, "headerlen is %d, datalen is %d", headerlen, datalen); if (pts != -1) { /* Check for pts overflow */ if (mpeg_demux->last_pts != -1) { gint32 diff = pts - mpeg_demux->last_pts; if (diff > -4 * CLOCK_FREQ && diff < 4 * CLOCK_FREQ) pts = mpeg_demux->last_pts + diff; } mpeg_demux->last_pts = pts; timestamp = PARSE_CLASS (mpeg_parse)->adjust_ts (mpeg_parse, MPEGTIME_TO_GSTTIME (pts)); /* this apparently happens for some input were headers are * rewritten to make time start at zero... */ if ((gint64) timestamp < 0) timestamp = 0; } else { timestamp = GST_CLOCK_TIME_NONE; } if (id == 0xBD) { /* Private stream 1. */ GST_DEBUG_OBJECT (mpeg_demux, "we have a private 1 packet"); ret = CLASS (mpeg_demux)->process_private (mpeg_demux, buffer, 0, timestamp, headerlen, datalen); } else if (id == 0xBF) { /* Private stream 2. */ GST_DEBUG_OBJECT (mpeg_demux, "we have a private 2 packet"); ret = CLASS (mpeg_demux)->process_private (mpeg_demux, buffer, 1, timestamp, headerlen, datalen); } else if (id >= 0xC0 && id <= 0xDF) { /* Audio. */ GST_DEBUG_OBJECT (mpeg_demux, "we have an audio packet"); outstream = CLASS (mpeg_demux)->get_audio_stream (mpeg_demux, id - 0xC0, GST_MPEG_DEMUX_AUDIO_MPEG, NULL); ret = CLASS (mpeg_demux)->send_subbuffer (mpeg_demux, outstream, buffer, timestamp, headerlen + 4, datalen); } else if (id >= 0xE0 && id <= 0xEF) { /* Video. */ gint mpeg_version = !GST_MPEG_PARSE_IS_MPEG2 (mpeg_demux) ? 1 : 2; GST_DEBUG_OBJECT (mpeg_demux, "we have a video packet"); outstream = CLASS (mpeg_demux)->get_video_stream (mpeg_demux, id - 0xE0, GST_MPEG_DEMUX_VIDEO_MPEG, &mpeg_version); ret = CLASS (mpeg_demux)->send_subbuffer (mpeg_demux, outstream, buffer, timestamp, headerlen + 4, datalen); } else if (id == 0xBE) { /* padding stream */ GST_DEBUG_OBJECT (mpeg_demux, "we have a padding packet"); } else { GST_WARNING_OBJECT (mpeg_demux, "unknown stream id 0x%02x", id); } return ret; }