Example #1
0
static pj_status_t opus_codec_parse(pjmedia_codec *codec, void *pkt,
                                    pj_size_t pkt_size, const pj_timestamp *ts,
                                    unsigned *frame_cnt,
                                    pjmedia_frame frames[]) {
  struct opus_private *opus;
  unsigned char toc;
  const unsigned char *raw_frames[48];
  short size[48];
  int payload_offset, samples_per_frame;
  unsigned i;

  PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);

  opus = (struct opus_private *)codec->codec_data;

  *frame_cnt =
      opus_packet_parse(pkt, pkt_size, &toc, raw_frames, size, &payload_offset);

  samples_per_frame = opus_packet_get_samples_per_frame(pkt, opus->externalFs);

#if _TRACE_OPUS
  PJ_LOG(4, (THIS_FILE,
             "Pkt info : bw -> %d , spf -> %d, offset %d, packet_size %d",
             opus_packet_get_bandwidth(pkt), samples_per_frame, payload_offset,
             pkt_size));
#endif

  for (i = 0; i < *frame_cnt; i++) {
    frames[i].type = PJMEDIA_FRAME_TYPE_AUDIO;
    frames[i].bit_info = (((unsigned)ts->u64 & 0xFFFF) << 16) |
                         (((unsigned)pkt & 0xFF) << 8) | i;
    frames[i].buf = pkt;
    frames[i].size = pkt_size;
    frames[i].timestamp.u64 =
        ts->u64 * opus->externalFs / OPUS_CLOCK_RATE + i * samples_per_frame;
#if _TRACE_OPUS
    PJ_LOG(4, (THIS_FILE, "parsed %d of %d", frames[i].size, *frame_cnt));
#endif
  }

  return PJ_SUCCESS;
}
Example #2
0
/**
 * Output debug information regarding the state of a single Opus packet
 */
void DebugFrameInfoInternal(const uint8* PacketData, uint32 PacketLength, uint32 SampleRate, bool bEncode)
{
	int32 NumFrames = opus_packet_get_nb_frames(PacketData, PacketLength);
	if (NumFrames == OPUS_BAD_ARG || NumFrames == OPUS_INVALID_PACKET)
	{
		UE_LOG(LogVoice, Warning, TEXT("opus_packet_get_nb_frames: Invalid voice packet data!"));
	}

	int32 NumSamples = opus_packet_get_nb_samples(PacketData, PacketLength, SampleRate);
	if (NumSamples == OPUS_BAD_ARG || NumSamples == OPUS_INVALID_PACKET)
	{
		UE_LOG(LogVoice, Warning, TEXT("opus_packet_get_nb_samples: Invalid voice packet data!"));
	}

	int32 NumSamplesPerFrame = opus_packet_get_samples_per_frame(PacketData, SampleRate);
	int32 Bandwidth = opus_packet_get_bandwidth(PacketData);

	const TCHAR* BandwidthStr = NULL;
	switch (Bandwidth)
	{
	case OPUS_BANDWIDTH_NARROWBAND: // Narrowband (4kHz bandpass)
		BandwidthStr = TEXT("NB");
		break;
	case OPUS_BANDWIDTH_MEDIUMBAND: // Mediumband (6kHz bandpass)
		BandwidthStr = TEXT("MB");
		break;
	case OPUS_BANDWIDTH_WIDEBAND: // Wideband (8kHz bandpass)
		BandwidthStr = TEXT("WB");
		break;
	case OPUS_BANDWIDTH_SUPERWIDEBAND: // Superwideband (12kHz bandpass)
		BandwidthStr = TEXT("SWB");
		break;
	case OPUS_BANDWIDTH_FULLBAND: // Fullband (20kHz bandpass)
		BandwidthStr = TEXT("FB");
		break;
	case OPUS_INVALID_PACKET: 
	default:
		BandwidthStr = TEXT("Invalid");
		break;
	}

	/*
	 *	0
	 *	0 1 2 3 4 5 6 7
	 *	+-+-+-+-+-+-+-+-+
	 *	| config  |s| c |
	 *	+-+-+-+-+-+-+-+-+
	 */
	uint8 TOC;
	// (max 48 x 2.5ms frames in a packet = 120ms)
	const uint8* frames[48];
	int16 size[48];
	int32 payload_offset = 0;
	int32 NumFramesParsed = opus_packet_parse(PacketData, PacketLength, &TOC, frames, size, &payload_offset);

	// Frame Encoding see http://tools.ietf.org/html/rfc6716#section-3.1
	int32 TOCEncoding = (TOC & 0xf8) >> 3;

	// Number of channels
	bool TOCStereo = (TOC & 0x4) != 0 ? true : false;

	// Number of frames and their configuration
	// 0: 1 frame in the packet
	// 1: 2 frames in the packet, each with equal compressed size
    // 2: 2 frames in the packet, with different compressed sizes
	// 3: an arbitrary number of frames in the packet
	int32 TOCMode = TOC & 0x3;

	if (bEncode)
	{
		UE_LOG(LogVoiceEncode, Verbose, TEXT("PacketLength: %d NumFrames: %d NumSamples: %d Bandwidth: %s Encoding: %d Stereo: %d FrameDesc: %d"),
			PacketLength, NumFrames, NumSamples, BandwidthStr, TOCEncoding, TOCStereo, TOCMode);
	}
	else
	{
		UE_LOG(LogVoiceDecode, Verbose, TEXT("PacketLength: %d NumFrames: %d NumSamples: %d Bandwidth: %s Encoding: %d Stereo: %d FrameDesc: %d"),
			PacketLength, NumFrames, NumSamples, BandwidthStr, TOCEncoding, TOCStereo, TOCMode);
	}
}
Example #3
0
static GstFlowReturn
gst_opus_parse_handle_frame (GstBaseParse * base,
    GstBaseParseFrame * frame, gint * skip)
{
  GstOpusParse *parse;
  guint8 *data;
  gsize size;
  guint32 packet_size;
  int ret = FALSE;
  const unsigned char *frames[48];
  unsigned char toc;
  short frame_sizes[48];
  int payload_offset;
  int packet_offset = 0;
  gboolean is_header, is_idheader, is_commentheader;
  GstMapInfo map;

  parse = GST_OPUS_PARSE (base);

  *skip = -1;

  gst_buffer_map (frame->buffer, &map, GST_MAP_READ);
  data = map.data;
  size = map.size;
  GST_DEBUG_OBJECT (parse,
      "Checking for frame, %" G_GSIZE_FORMAT " bytes in buffer", size);

  /* check for headers */
  is_idheader = gst_opus_header_is_id_header (frame->buffer);
  is_commentheader = gst_opus_header_is_comment_header (frame->buffer);
  is_header = is_idheader || is_commentheader;

  if (!is_header) {
    int nframes;

    /* Next, check if there's an Opus packet there */
    nframes =
        opus_packet_parse (data, size, &toc, frames, frame_sizes,
        &payload_offset);

    if (nframes < 0) {
      /* Then, check for the test vector framing */
      GST_DEBUG_OBJECT (parse,
          "No Opus packet found, trying test vector framing");
      if (size < 4) {
        GST_DEBUG_OBJECT (parse, "Too small");
        goto beach;
      }
      packet_size = GST_READ_UINT32_BE (data);
      GST_DEBUG_OBJECT (parse, "Packet size: %u bytes", packet_size);
      if (packet_size > MAX_PAYLOAD_BYTES) {
        GST_DEBUG_OBJECT (parse, "Too large");
        goto beach;
      }
      if (packet_size > size - 4) {
        GST_DEBUG_OBJECT (parse, "Truncated");
        goto beach;
      }
      nframes =
          opus_packet_parse (data + 8, packet_size, &toc, frames, frame_sizes,
          &payload_offset);
      if (nframes < 0) {
        GST_DEBUG_OBJECT (parse, "No test vector framing either");
        goto beach;
      }

      packet_offset = 8;

      /* for ad hoc framing, heed the framing, so we eat any padding */
      payload_offset = packet_size;
    } else {
      /* Add up all the frame sizes found */
      int f;
      for (f = 0; f < nframes; ++f)
        payload_offset += frame_sizes[f];
    }
  }

  if (is_header) {
    *skip = 0;
  } else {
    *skip = packet_offset;
    size = payload_offset;
  }

  GST_DEBUG_OBJECT (parse,
      "Got Opus packet at offset %d, %" G_GSIZE_FORMAT " bytes", *skip, size);
  ret = TRUE;

beach:
  gst_buffer_unmap (frame->buffer, &map);

  /* convert old style result to new one */
  if (!ret) {
    if (*skip < 0)
      *skip = 1;
    return GST_FLOW_OK;
  }

  /* always skip first if needed */
  if (*skip > 0)
    return GST_FLOW_OK;

  /* normalize again */
  if (*skip < 0)
    *skip = 0;

  /* not enough */
  if (size > map.size)
    return GST_FLOW_OK;

  /* FIXME some day ... should not mess with buffer itself */
  if (!parse->got_headers) {
    gst_buffer_replace (&frame->buffer,
        gst_buffer_copy_region (frame->buffer, GST_BUFFER_COPY_ALL, 0, size));
    gst_buffer_unref (frame->buffer);
  }

  ret = gst_opus_parse_parse_frame (base, frame);

  if (ret == GST_BASE_PARSE_FLOW_DROPPED) {
    frame->flags |= GST_BASE_PARSE_FRAME_FLAG_DROP;
    ret = GST_FLOW_OK;
  }
  if (ret == GST_FLOW_OK)
    ret = gst_base_parse_finish_frame (base, frame, size);

  return ret;
}