Beispiel #1
0
/**
 * tsmux_stream_initialize_pes_packet:
 * @stream: a #TsMuxStream
 *
 * Initializes the PES packet.
 *
 * Returns: TRUE if we the packet was initialized.
 */
gboolean
tsmux_stream_initialize_pes_packet (TsMuxStream * stream)
{
  if (stream->state != TSMUX_STREAM_STATE_HEADER)
    return TRUE;

  if (stream->pes_payload_size != 0) {
    /* Use prescribed fixed PES payload size */
    stream->cur_pes_payload_size = stream->pes_payload_size;
    tsmux_stream_find_pts_dts_within (stream, stream->cur_pes_payload_size,
        &stream->pts, &stream->dts);
  } else if (stream->is_video_stream) {
    /* Unbounded for video streams */
    stream->cur_pes_payload_size = 0;
    tsmux_stream_find_pts_dts_within (stream,
        tsmux_stream_bytes_in_buffer (stream), &stream->pts, &stream->dts);
  } else {
    /* Output a PES packet of all currently available bytes otherwise */
    stream->cur_pes_payload_size = tsmux_stream_bytes_in_buffer (stream);
    tsmux_stream_find_pts_dts_within (stream, stream->cur_pes_payload_size,
        &stream->pts, &stream->dts);
  }

  stream->pi.flags &= ~(TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS |
      TSMUX_PACKET_FLAG_PES_WRITE_PTS);

  if (stream->pts != -1 && stream->dts != -1)
    stream->pi.flags |= TSMUX_PACKET_FLAG_PES_WRITE_PTS_DTS;
  else {
    if (stream->pts != -1)
      stream->pi.flags |= TSMUX_PACKET_FLAG_PES_WRITE_PTS;
  }

  if (stream->buffers) {
    TsMuxStreamBuffer *buf = (TsMuxStreamBuffer *) (stream->buffers->data);
    if (buf->random_access) {
      stream->pi.flags |= TSMUX_PACKET_FLAG_RANDOM_ACCESS;
      stream->pi.flags |= TSMUX_PACKET_FLAG_ADAPTATION;
    }
  }

  return TRUE;
}
Beispiel #2
0
/**
 * tsmux_stream_bytes_avail:
 * @stream: a #TsMuxStream
 *
 * Calculate how much bytes are available.
 *
 * Returns: The number of bytes available.
 */
gint
tsmux_stream_bytes_avail (TsMuxStream * stream)
{
  gint bytes_avail;

  g_return_val_if_fail (stream != NULL, 0);

  if (stream->cur_pes_payload_size != 0)
    bytes_avail = stream->cur_pes_payload_size - stream->pes_bytes_written;
  else
    bytes_avail = tsmux_stream_bytes_in_buffer (stream);

  bytes_avail = MIN (bytes_avail, tsmux_stream_bytes_in_buffer (stream));

  /* Calculate the number of bytes available in the current PES */
  if (stream->state == TSMUX_STREAM_STATE_HEADER)
    bytes_avail += tsmux_stream_pes_header_length (stream);

  return bytes_avail;
}
Beispiel #3
0
static GstFlowReturn
mpegtsmux_collected (GstCollectPads * pads, MpegTsMux * mux)
{
  GstFlowReturn ret = GST_FLOW_OK;
  MpegTsPadData *best = NULL;

  GST_DEBUG_OBJECT (mux, "Pads collected");

  if (mux->first) {
    ret = mpegtsmux_create_streams (mux);
    if (G_UNLIKELY (ret != GST_FLOW_OK))
      return ret;

    best = mpegtsmux_choose_best_stream (mux);

    if (!mpegtsdemux_prepare_srcpad (mux)) {
      GST_DEBUG_OBJECT (mux, "Failed to send new segment");
      goto new_seg_fail;
    }

    mux->first = FALSE;
  } else {
    best = mpegtsmux_choose_best_stream (mux);
  }

  if (best != NULL) {
    TsMuxProgram *prog = best->prog;
    GstBuffer *buf = best->queued_buf;
    gint64 pts = -1;
    gboolean delta = TRUE;

    if (prog == NULL) {
      GST_ELEMENT_ERROR (mux, STREAM, MUX, ("Stream is not associated with "
              "any program"), (NULL));
      return GST_FLOW_ERROR;
    }

    if (G_UNLIKELY (prog->pcr_stream == NULL)) {
      if (best) {
        /* Take the first data stream for the PCR */
        GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
            "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
            MPEG_TS_PAD_DATA (best)->pid, MPEG_TS_PAD_DATA (best)->prog_id);

        /* Set the chosen PCR stream */
        tsmux_program_set_pcr_stream (prog, best->stream);
      }
    }

    g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
    if (best->stream->is_video_stream)
      delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
    GST_DEBUG_OBJECT (mux, "delta: %d", delta);

    GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
        "Chose stream for output (PID: 0x%04x)", best->pid);

    if (GST_CLOCK_TIME_IS_VALID (best->cur_ts)) {
      pts = GSTTIME_TO_MPEGTIME (best->cur_ts);
      GST_DEBUG_OBJECT (mux, "Buffer has TS %" GST_TIME_FORMAT " pts %"
          G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_ts), pts);
    }

    tsmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf), buf, pts, -1, !delta);
    best->queued_buf = NULL;

    mux->is_delta = delta;
    while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
      if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
        GST_DEBUG_OBJECT (mux, "Failed to write data packet");
        goto write_fail;
      }
    }
    if (prog->pcr_stream == best->stream) {
      mux->last_ts = best->last_ts;
    }
  } else {
    /* FIXME: Drain all remaining streams */
    /* At EOS */
    gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
  }

  return ret;
new_seg_fail:
  return GST_FLOW_ERROR;
write_fail:
  /* FIXME: Failed writing data for some reason. Should set appropriate error */
  return mux->last_flow_ret;
}
Beispiel #4
0
static GstFlowReturn
mpegtsmux_collected (GstCollectPads * pads, MpegTsMux * mux)
{
  GstFlowReturn ret = GST_FLOW_OK;
  MpegTsPadData *best = NULL;

  GST_DEBUG_OBJECT (mux, "Pads collected");

  if (mux->first) {
    ret = mpegtsmux_create_streams (mux);
    if (G_UNLIKELY (ret != GST_FLOW_OK))
      return ret;

    best = mpegtsmux_choose_best_stream (mux);

    if (mux->pcr_stream == NULL) {
      if (best) {
        /* Take the first data stream for the PCR */
        GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best), "Use stream as PCR");
        mux->pcr_stream = best->stream;
      }
    }

    /* Set the chosen PCR stream */
    g_return_val_if_fail (mux->pcr_stream != NULL, GST_FLOW_ERROR);
    tsmux_program_set_pcr_stream (mux->program, mux->pcr_stream);

    if (!mpegtsdemux_prepare_srcpad (mux)) {
      GST_DEBUG_OBJECT (mux, "Failed to send new segment");
      goto new_seg_fail;
    }

    mux->first = FALSE;
  } else {
    best = mpegtsmux_choose_best_stream (mux);
  }

  if (best != NULL) {
    GstBuffer *buf = best->queued_buf;
    gint64 pts = -1;

    g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);

    GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
        "Chose stream for output (PID: 0x%04x)", best->pid);

    if (GST_CLOCK_TIME_IS_VALID (best->cur_ts)) {
      pts = GSTTIME_TO_MPEGTIME (best->cur_ts);
      GST_DEBUG_OBJECT (mux, "Buffer has TS %" GST_TIME_FORMAT " pts %"
          G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_ts), pts);
    }

    tsmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf), buf, pts, -1);
    best->queued_buf = NULL;

    while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
      if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
        GST_DEBUG_OBJECT (mux, "Failed to write data packet");
        goto write_fail;
      }
    }
    if (mux->pcr_stream == best->stream) {
      mux->last_ts = best->last_ts;
    }
  } else {
    /* FIXME: Drain all remaining streams */
    /* At EOS */
    gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
  }

  return ret;
new_seg_fail:
  return GST_FLOW_ERROR;
write_fail:
  /* FIXME: Failed writing data for some reason. Should set appropriate error */
  return mux->last_flow_ret;
}
Beispiel #5
0
static GstFlowReturn
mpegtsmux_collected (GstCollectPads2 * pads, MpegTsMux * mux)
{
  GstFlowReturn ret = GST_FLOW_OK;
  MpegTsPadData *best = NULL;

  GST_DEBUG_OBJECT (mux, "Pads collected");

  if (G_UNLIKELY (mux->first)) {
    ret = mpegtsmux_create_streams (mux);
    if (G_UNLIKELY (ret != GST_FLOW_OK))
      return ret;

    mpegtsdemux_prepare_srcpad (mux);

    mux->first = FALSE;
  }

  best = mpegtsmux_choose_best_stream (mux);

  if (best != NULL) {
    TsMuxProgram *prog = best->prog;
    GstBuffer *buf = best->queued_buf;
    gint64 pts = -1;
    gboolean delta = TRUE;

    if (prog == NULL) {
      GST_ELEMENT_ERROR (mux, STREAM, MUX,
          ("Stream on pad %" GST_PTR_FORMAT
              " is not associated with any program", COLLECT_DATA_PAD (best)),
          (NULL));
      return GST_FLOW_ERROR;
    }

    if (mux->force_key_unit_event != NULL && best->stream->is_video_stream) {
      GstEvent *event;

      event = check_pending_key_unit_event (mux->force_key_unit_event,
          &best->collect.segment, GST_BUFFER_TIMESTAMP (buf),
          GST_BUFFER_FLAGS (buf), mux->pending_key_unit_ts);
      if (event) {
        GstClockTime running_time;
        guint count;
        GList *cur;

        mux->pending_key_unit_ts = GST_CLOCK_TIME_NONE;
        gst_event_replace (&mux->force_key_unit_event, NULL);

        gst_video_event_parse_downstream_force_key_unit (event,
            NULL, NULL, &running_time, NULL, &count);

        GST_INFO_OBJECT (mux, "pushing downstream force-key-unit event %d "
            "%" GST_TIME_FORMAT " count %d", gst_event_get_seqnum (event),
            GST_TIME_ARGS (running_time), count);
        gst_pad_push_event (mux->srcpad, event);

        /* output PAT */
        mux->tsmux->last_pat_ts = -1;

        /* output PMT for each program */
        for (cur = g_list_first (mux->tsmux->programs); cur != NULL;
            cur = g_list_next (cur)) {
          TsMuxProgram *program = (TsMuxProgram *) cur->data;

          program->last_pmt_ts = -1;
        }
        tsmux_program_set_pcr_stream (prog, NULL);
      }
    }

    if (G_UNLIKELY (prog->pcr_stream == NULL)) {
      /* Take the first data stream for the PCR */
      GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
          "Use stream (pid=%d) from pad as PCR for program (prog_id = %d)",
          MPEG_TS_PAD_DATA (best)->pid, MPEG_TS_PAD_DATA (best)->prog_id);

      /* Set the chosen PCR stream */
      tsmux_program_set_pcr_stream (prog, best->stream);
    }

    g_return_val_if_fail (buf != NULL, GST_FLOW_ERROR);
    if (best->stream->is_video_stream)
      delta = GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT);
    GST_DEBUG_OBJECT (mux, "delta: %d", delta);

    GST_DEBUG_OBJECT (COLLECT_DATA_PAD (best),
        "Chose stream for output (PID: 0x%04x)", best->pid);

    if (GST_CLOCK_TIME_IS_VALID (best->cur_ts)) {
      pts = GSTTIME_TO_MPEGTIME (best->cur_ts);
      GST_DEBUG_OBJECT (mux, "Buffer has TS %" GST_TIME_FORMAT " pts %"
          G_GINT64_FORMAT, GST_TIME_ARGS (best->cur_ts), pts);
    }

    tsmux_stream_add_data (best->stream, GST_BUFFER_DATA (buf),
        GST_BUFFER_SIZE (buf), buf, pts, -1, !delta);
    best->queued_buf = NULL;

    mux->is_delta = delta;
    while (tsmux_stream_bytes_in_buffer (best->stream) > 0) {
      if (!tsmux_write_stream_packet (mux->tsmux, best->stream)) {
        /* Failed writing data for some reason. Set appropriate error */
        GST_DEBUG_OBJECT (mux, "Failed to write data packet");
        GST_ELEMENT_ERROR (mux, STREAM, MUX,
            ("Failed writing output data to stream %04x", best->stream->id),
            (NULL));
        goto write_fail;
      }
    }
    if (prog->pcr_stream == best->stream) {
      mux->last_ts = best->last_ts;
    }
  } else {
    /* FIXME: Drain all remaining streams */
    /* At EOS */
    gst_pad_push_event (mux->srcpad, gst_event_new_eos ());
  }

  return ret;
write_fail:
  return mux->last_flow_ret;
}