⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isma_rtp_bytestream.cpp

📁 jpeg and mpeg 编解码技术源代码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
 * The contents of this file are subject to the Mozilla Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/MPL/
 * 
 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.
 * 
 * The Original Code is MPEG4IP.
 * 
 * The Initial Developer of the Original Code is Cisco Systems Inc.
 * Portions created by Cisco Systems Inc. are
 * Copyright (C) Cisco Systems Inc. 2001.  All Rights Reserved.
 * 
 * Contributor(s): 
 *              Bill May        wmay@cisco.com
 */

#include "systems.h"
#include <rtp/rtp.h>
#include <rtp/memory.h>
#include <sdp/sdp.h> // for NTP_TO_UNIX_TIME
#include "bitstream/bitstream.h"
#include "isma_rtp_bytestream.h"
#include "our_config_file.h"
#include <mp4util/mpeg4_audio_config.h>
//#define DEBUG_ISMA_AAC

#ifdef _WIN32
DEFINE_MESSAGE_MACRO(isma_message, "ismartp")
#else
#define isma_message(loglevel, fmt...) message(loglevel, "ismartp", fmt)
#endif

/*
 * Isma rtp bytestream has a potential set of headers at the beginning
 * of each rtp frame.  This can interleave frames in different packets
 */
CIsmaAudioRtpByteStream::CIsmaAudioRtpByteStream (format_list_t *media_fmt,
						  fmtp_parse_t *fmtp,
						  unsigned int rtp_pt,
						  int ondemand,
						  uint64_t tps,
						  rtp_packet **head, 
						  rtp_packet **tail,
						  int rtp_seq_set,
						  uint16_t rtp_base_seq,
						  int rtp_ts_set,
						  uint32_t rtp_base_ts,
						  int rtcp_received,
						  uint32_t ntp_frac,
						  uint32_t ntp_sec,
						  uint32_t rtp_ts) :
  CRtpByteStreamBase("ismaaac", media_fmt, rtp_pt, ondemand, tps, head, tail, 
		     rtp_seq_set, rtp_base_seq, rtp_ts_set, rtp_base_ts,
		     rtcp_received, ntp_frac, ntp_sec, rtp_ts)
{
#ifdef ISMA_RTP_DUMP_OUTPUT_TO_FILE
  m_outfile = fopen("isma.aac", "w");
#endif
  m_frame_data_head = NULL;
  m_frame_data_on = NULL;
  m_frame_data_free = NULL;
  isma_frame_data_t *p;
  for (m_frame_data_max = 0; m_frame_data_max < 25; m_frame_data_max++) {
    p = (isma_frame_data_t *)malloc(sizeof(isma_frame_data_t));
    p->frame_data_next = m_frame_data_free;
    m_frame_data_free = p;
  }
  mpeg4_audio_config_t audio_config;
  decode_mpeg4_audio_config(fmtp->config_binary,
			    fmtp->config_binary_len,
			    &audio_config);
  if (audio_object_type_is_aac(&audio_config)) {
    m_rtp_ts_add = audio_config.codec.aac.frame_len_1024 != 0 ? 1024 : 960;
  } else {
    m_rtp_ts_add = audio_config.codec.celp.samples_per_frame;
    isma_message(LOG_DEBUG, "celp spf is %d", m_rtp_ts_add);
  }
  m_rtp_ts_add = (m_rtp_ts_add * media_fmt->rtpmap->clock_rate) /
    audio_config.frequency;
  isma_message(LOG_DEBUG, 
	       "Rtp ts add is %d (%d %d)", m_rtp_ts_add,
	       media_fmt->rtpmap->clock_rate, 
	       audio_config.frequency);
  m_fmtp = *fmtp;
  m_min_first_header_bits = m_fmtp.size_length + m_fmtp.index_length;
  m_min_header_bits = m_fmtp.size_length + m_fmtp.index_delta_length;
  if (m_fmtp.CTS_delta_length > 0) {
    m_min_header_bits++;
    m_min_first_header_bits++;
  }
  if (m_fmtp.DTS_delta_length > 0) {
    m_min_header_bits++;
    m_min_first_header_bits++;
  }
  isma_message(LOG_DEBUG, "min headers are %d %d", m_min_first_header_bits,
	       m_min_header_bits);

  m_min_header_bits += m_fmtp.auxiliary_data_size_length;
  m_min_first_header_bits += m_fmtp.auxiliary_data_size_length;
  m_frag_reass_buffer = NULL;
  m_frag_reass_size_max = 0;
}

CIsmaAudioRtpByteStream::~CIsmaAudioRtpByteStream (void)
{
#ifdef ISMA_RTP_DUMP_OUTPUT_TO_FILE
  fclose(m_outfile);
#endif
  isma_frame_data_t *p;
  
  if (m_frag_reass_buffer != NULL) {
    free(m_frag_reass_buffer);
    m_frag_reass_buffer = NULL;
  }
  if (m_frame_data_on != NULL) {
    m_frame_data_on->frame_data_next = m_frame_data_head;
    m_frame_data_head = m_frame_data_on;
    m_frame_data_on = NULL;
  }
  while (m_frame_data_free != NULL) {
    p = m_frame_data_free;
    m_frame_data_free = p->frame_data_next;
    free(p);
  }
  while (m_frame_data_head != NULL) {
    p = m_frame_data_head;
    // if fragmented frame, free all frag_data
    if (p->is_fragment == 1) {
      isma_frag_data_t * q = p->frag_data;
      while (q != NULL) {
	p->frag_data = q->frag_data_next;
	free(q);
	q = p->frag_data;
      }
    }
    m_frame_data_head = p->frame_data_next;
    free(p);
  }
}

int CIsmaAudioRtpByteStream::insert_frame_data (isma_frame_data_t *frame_data)
{
  SDL_LockMutex(m_rtp_packet_mutex);
  if (m_frame_data_head == NULL) {
    m_frame_data_head = frame_data;
  } else {
    int32_t diff;
    isma_frame_data_t *p, *q;
    q = NULL;
    p = m_frame_data_head;

    do {
      diff = frame_data->rtp_timestamp - p->rtp_timestamp;
      if (diff == 0) {
	isma_message(LOG_ERR, "Duplicate timestamp of %x found in RTP packet",
		     frame_data->rtp_timestamp);
	isma_message(LOG_DEBUG, 
		     "Seq number orig %d new %d", 
		     p->pak->rtp_pak_seq, frame_data->pak->rtp_pak_seq); 
	// if fragmented frame, free all frag_data
	if (frame_data->is_fragment == 1) {
	  isma_frag_data_t * p = NULL;
	  while ((p = frame_data->frag_data) != NULL) {
	    frame_data->frag_data = p->frag_data_next;
	    free(p);
	  }
	}
	// put frame_data on free list
	frame_data->frame_data_next = m_frame_data_free;
	m_frame_data_free = frame_data;

	SDL_UnlockMutex(m_rtp_packet_mutex);
	return 1;
      } else if (diff < 0) {
	if (q == NULL) {
	  frame_data->frame_data_next = m_frame_data_head;
	  m_frame_data_head = frame_data;
	} else {
	  q->frame_data_next = frame_data;
	  frame_data->frame_data_next = p;
	}
	SDL_UnlockMutex(m_rtp_packet_mutex);
	return 0;
      }
      q = p;
      p = p->frame_data_next;
    } while (p != NULL);
    // insert at end;
    q->frame_data_next = frame_data;

  }
  SDL_UnlockMutex(m_rtp_packet_mutex);
  return 0;
}

void CIsmaAudioRtpByteStream::get_au_header_bits (void)
{
  uint32_t temp;
  if (m_fmtp.CTS_delta_length > 0) {
    m_header_bitstream.getbits(1, &temp);
    if (temp > 0) {
      m_header_bitstream.getbits(m_fmtp.CTS_delta_length, &temp);
    }
  }
  if (m_fmtp.DTS_delta_length > 0) {
    m_header_bitstream.getbits(1, &temp);
    if (temp > 0) {
      m_header_bitstream.getbits(m_fmtp.DTS_delta_length, &temp);
    }
  }
}

// check where need to lock 
void CIsmaAudioRtpByteStream::cleanup_frag (isma_frame_data_t * frame_data)
{
  // free all frag_data for this frame
  isma_frag_data_t * p = NULL;
  while ((p = frame_data->frag_data) != NULL) {
    frame_data->frag_data = p->frag_data_next;
    free(p);
  } 
  // now put frame_data back on free list
  SDL_LockMutex(m_rtp_packet_mutex);
  frame_data->frame_data_next = m_frame_data_free;
  m_frame_data_free = frame_data;
  SDL_UnlockMutex(m_rtp_packet_mutex);
  return;
}

// Frame is fragmented.
// Process next RTP paks until have the entire frame.
// Paks will be in order in the queue, but maybe some missing?
// So if process pkt w/ Mbit set (last of fragm) and total < frameLength
// ignore pkt.
// Insert frame data only after got all fragments for the frame.
int CIsmaAudioRtpByteStream::process_fragment (rtp_packet *pak, 
					       isma_frame_data_t *frame_data)
{
  uint16_t seq = pak->rtp_pak_seq; 
  uint32_t ts = pak->rtp_pak_ts;
  isma_frag_data_t *cur = NULL;
  int read_mBit = 0;
  uint32_t total_len = 0; 
  frame_data->is_fragment = 1;
  do {
    if (read_mBit == 1) {
      // get rid of frame_data - last frag seen but total length wrong
      cleanup_frag(frame_data);
      isma_message(LOG_ERR, "Error processing frag: early mBit");
      return (1); 
    }
    if (pak == NULL) {
      cleanup_frag(frame_data);
      isma_message(LOG_ERR, "Error processing frag: not enough packets");
      return (1);
    }
    // check if ts and rtp seq numbers are ok, and lengths match
    if (ts != pak->rtp_pak_ts) {
      cleanup_frag(frame_data);
      isma_message(LOG_ERR, 
		   "Error processing frag: wrong ts: ts= %x, pak->ts = %x", 
		   ts, pak->rtp_pak_ts);
      return (1);
    }
    if (seq != pak->rtp_pak_seq) {
      cleanup_frag(frame_data);
      isma_message(LOG_ERR, "Error processing frag: wrong seq num");
      return (1);
    }
    // insert fragment info
    isma_frag_data_t *p = (isma_frag_data_t *)
      malloc(sizeof(isma_frag_data_t));
    if (p == NULL) {
      isma_message(LOG_ERR, "Error processing frag: can't malloc");
      remove_packet_rtp_queue(pak, 0);
      return (1);
    }
    if (cur == NULL) {
      frame_data->frag_data = p;
      cur = p;		
    } else {
      cur->frag_data_next = p;
      cur = p;
    }
    cur->frag_data_next = NULL;
    cur->pak = pak; 
    // length in bits
    uint16_t header_len = ntohs(*(unsigned short *)pak->rtp_data);
    m_header_bitstream.init(&pak->rtp_data[sizeof(uint16_t)], header_len);
    // frag_ptr should just point to beginning of data in pkt
    uint32_t header_len_bytes = ((header_len + 7) / 8) + sizeof(uint16_t);
    cur->frag_ptr =  &pak->rtp_data[header_len_bytes];
    cur->frag_len = pak->rtp_data_len - header_len_bytes;
    // if aux data, move frag pointer
    if (m_fmtp.auxiliary_data_size_length > 0) {
      m_header_bitstream.byte_align();
      uint32_t aux_len;
      m_header_bitstream.getbits(m_fmtp.auxiliary_data_size_length, &aux_len);
      aux_len = (aux_len + 7) / 8;
      cur->frag_ptr += aux_len;
      cur->frag_len -= aux_len;
    }
    total_len += cur->frag_len;
#ifdef DEBUG_ISMA_RTP_FRAGS
    isma_message(LOG_DEBUG, 
		 "rtp seq# %d, fraglen: %d, ts: %x", 
		 pak->seq, cur->frag_len, pak->ts);
#endif	
    seq = pak->rtp_pak_seq + 1;
    if (pak->rtp_pak_m) 
      read_mBit = 1;
    remove_packet_rtp_queue(pak, 0);
    pak = m_head; // get next pkt in the queue
  } while (total_len < frame_data->frame_len);

  // insert frame and return
  int error = insert_frame_data(frame_data);
  frame_data->last_in_pak = 1; // only one frame in pak
  // no need to remove pkt from queue, done at the end of do-while
  return (error);
}

void CIsmaAudioRtpByteStream::process_packet_header (void)
{
  rtp_packet *pak;
  uint32_t frame_len;
  uint16_t header_len;
  uint32_t retvalue;

  pak = m_head;
  if (pak == NULL) {
    return;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -