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

📄 mpeg3_rtp_bytestream.cpp

📁 jpeg and mpeg 编解码技术源代码
💻 CPP
字号:
/*
 * 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 "mpeg3_rtp_bytestream.h"
#include "our_config_file.h"
//#define DEBUG_RTP_PAKS 1
#ifdef _WIN32
DEFINE_MESSAGE_MACRO(rtp_message, "rtpbyst")
#else
#define rtp_message(loglevel, fmt...) message(loglevel, "rtpbyst", fmt)
#endif
static rtp_packet *end_of_pak (rtp_packet *start)
{
  while (start->rtp_next->rtp_pak_ts == start->rtp_pak_ts) 
    start = start->rtp_next;

  return start;
}

CMpeg3RtpByteStream::CMpeg3RtpByteStream(unsigned int rtp_pt,
					 format_list_t *fmt,
					 int ondemand,
					 uint64_t tickpersec,
					 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) :
  CRtpByteStream("mpeg3", fmt, rtp_pt, ondemand, tickpersec, head, tail,
		 rtp_seq_set, rtp_base_seq, rtp_ts_set, rtp_base_ts, 
		 rtcp_received, ntp_frac, ntp_sec, rtp_ts)
{
}

uint64_t CMpeg3RtpByteStream::start_next_frame (uint8_t **buffer, 
						uint32_t *buflen,
						void **ud)
{
  uint16_t seq = 0;
  uint32_t ts = 0, outts;
  uint64_t timetick;
  int first = 0;
  int finished = 0;
  rtp_packet *rpak;
  int32_t diff;
  int correct_hdr;
  int dropped_seq;

  diff = m_buffer_len - m_bytes_used;

  m_doing_add = 0;
  if (diff > 2) {
    // Still bytes in the buffer...
    *buffer = m_buffer + m_bytes_used;
    *buflen = diff;
#ifdef DEBUG_RTP_PAKS
    rtp_message(LOG_DEBUG, "%s Still left - %d bytes", m_name, *buflen);
#endif
    return (m_last_realtime);
  }
  int frame_type;
  m_buffer_len = 0;
  dropped_seq = 0;
  while (finished == 0) {
    rpak = m_head;
    if (rpak == NULL) {
      *buffer = NULL;
      return 0;
    }
    remove_packet_rtp_queue(rpak, 0);

    correct_hdr = 1;
    if (m_next_seq != rpak->rtp_pak_seq) {
      correct_hdr = 0;
      rtp_message(LOG_INFO, "%s missing rtp sequence - should be %u is %u", 
		  m_name, m_next_seq, rpak->rtp_pak_seq);
      first = 0;
    } else {
      if (first == 0) {
	ts = rpak->rtp_pak_ts;
	first = 1;
      } else {
	if (ts != rpak->rtp_pak_ts) {
	  rtp_message(LOG_INFO, 
		      "%s timestamp error - seq %u should be %x is %x", 
		      m_name, seq, ts, rpak->rtp_pak_ts);
	  correct_hdr = 0;
	}
	ts = rpak->rtp_pak_ts;
      }
    }
    if (correct_hdr == 0) {
      m_buffer_len = 0;
    } else {
      dropped_seq = 1;
    }

    m_next_seq = rpak->rtp_pak_seq + 1; // handles wrap correctly

    uint8_t *from;
    uint32_t len;
    m_skip_on_advance_bytes = 4;
    if ((*rpak->rtp_data & 0x4) != 0) {
      m_skip_on_advance_bytes = 8;
      if ((rpak->rtp_data[4] & 0x40) != 0) {
      }
    }
    frame_type = rpak->rtp_data[2] & 0x7;
    from = (uint8_t *)rpak->rtp_data + m_skip_on_advance_bytes;
    len = rpak->rtp_data_len - m_skip_on_advance_bytes;
    if ((m_buffer_len + len) > m_buffer_len_max) {
      // realloc
      m_buffer_len_max = m_buffer_len + len + 1024;
      m_buffer = (uint8_t *)realloc(m_buffer, m_buffer_len_max);
    }
    memcpy(m_buffer + m_buffer_len, 
	   from,
	   len);
    m_buffer_len += len;
  
    if (rpak->rtp_pak_m == 1) {
      finished = 1;
    }
    xfree(rpak);
  }
  m_bytes_used = 0;
  *buffer = m_buffer + m_bytes_used;
  *buflen = m_buffer_len - m_bytes_used;
#ifdef DEBUG_RTP_PAKS
  rtp_message(LOG_DEBUG, "%s buffer len %d", m_name, m_buffer_len);
#endif
  if (dropped_seq) {
    outts = calc_this_ts_from_future(frame_type, ts);
  } else {
    if (m_have_prev_frame_type) {
      if (frame_type < 3) {
	// B frame
	outts = ts + m_rtp_frame_add;
      } else {
	outts = m_prev_ts + m_rtp_frame_add;
      }
    } else 
      outts = calc_this_ts_from_future(frame_type, ts);
  }
#ifdef MPEG3_RTP_TIME
  rtp_message(LOG_DEBUG, "frame type %d pak ts %u out ts %u", frame_type, 
	      ts, outts);
#endif
  m_have_prev_frame_type = 1;
  m_prev_frame_type = frame_type;
  m_prev_ts = outts;

  if (m_rtpinfo_set_from_pak != 0) {
    if (outts < m_rtp_base_ts) {
      m_rtp_base_ts = outts;
    }
    m_rtpinfo_set_from_pak = 0;
  }
  m_ts = outts;
  timetick = rtp_ts_to_msec(outts, m_wrap_offset);
  
  return (timetick);
}

uint32_t CMpeg3RtpByteStream::calc_this_ts_from_future (int frame_type,
						   uint32_t pak_ts)
{
  int new_frame_type;
  uint32_t outts;
  if (frame_type >= 3) {
    // B frame - ts is always pak_ts + 1 frame time
    return pak_ts + m_rtp_frame_add;
  }

  SDL_LockMutex(m_rtp_packet_mutex);
  if (m_head->rtp_pak_seq != m_next_seq) {
    outts = m_head->rtp_pak_ts - m_rtp_frame_add; // not accurate, but close enuff
  } else {
    new_frame_type = m_head->rtp_data[2] & 0x7;
    if (new_frame_type >= 3) {
      outts = m_head->rtp_pak_ts;
    }  else if (frame_type == 2 ||
		(frame_type == 1 && new_frame_type == 1)) {
    // I frame followed by I frame, P frame followed by I or P frame
      outts = pak_ts;
    } else {
      // I frame followed by P frame
      rtp_packet *next_pak = end_of_pak(m_head);
      next_pak = next_pak->rtp_next;
      new_frame_type = next_pak->rtp_data[2] & 0x7;
      if (new_frame_type < 3) {
	outts = pak_ts;
      } else {
	outts = next_pak->rtp_pak_ts - (2 * m_rtp_frame_add);
      }
    }
  }
  SDL_UnlockMutex(m_rtp_packet_mutex);
  return outts;
}
							
int CMpeg3RtpByteStream::skip_next_frame (uint64_t *pts, int *hasSyncFrame,
					  uint8_t **buffer, 
					  uint32_t *buflen)
{
  uint64_t ts;
  *hasSyncFrame = -1;  // we don't know if we have a sync frame
  m_buffer_len = m_bytes_used = 0;
  if (m_head == NULL) return 0;
  ts = m_head->rtp_pak_ts;
  do {
    remove_packet_rtp_queue(m_head, 1);
  } while (m_head != NULL && m_head->rtp_pak_ts == ts);

  if (m_head == NULL) return 0;
  init();
  m_buffer_len = m_bytes_used = 0;
  ts = start_next_frame(buffer, buflen, NULL);
  *pts = ts;
  return (1);
}

int CMpeg3RtpByteStream::have_no_data (void)
{
  rtp_packet *temp, *first;
  if (m_head == NULL) return TRUE;
  first = temp = m_head;
  int count = 0;
  SDL_LockMutex(m_rtp_packet_mutex);
  do {
    if (temp->rtp_pak_m == 1) {
      count++;
      if (count > 1) {
	SDL_UnlockMutex(m_rtp_packet_mutex);
	return FALSE;
      }
    }
    temp = temp->rtp_next;
  } while (temp != NULL && temp != first);
  SDL_UnlockMutex(m_rtp_packet_mutex);
  return TRUE;
}


void CMpeg3RtpByteStream::rtp_done_buffering (void) 
{
  rtp_packet *p, *q;
  int had_b;
  SDL_LockMutex(m_rtp_packet_mutex);

  m_next_seq = m_head->rtp_pak_seq;


  p = end_of_pak(m_head);
  had_b = 0;
  while (p != m_head) {
    q = end_of_pak(p->rtp_next);
    if ((p->rtp_data[2] & 0x7) == 3) {
      // B frame 
      had_b = 1;
      if ((((q->rtp_pak_seq + 1) & 0xffff) == q->rtp_next->rtp_pak_seq) &&
	  ((q->rtp_next->rtp_data[2] & 0x7) == 3)) {
	// 2 consec b frames
	q = q->rtp_next;
	m_rtp_frame_add  = q->rtp_pak_ts - p->rtp_pak_ts;
#ifdef MPEG3_RTP_TIME
	rtp_message(LOG_DEBUG, "2 consec b frames %d", m_rtp_frame_add);
#endif
	SDL_UnlockMutex(m_rtp_packet_mutex);
	return;
      }
    }
    p = q->rtp_next;
  }
  if (had_b == 0) {
    // no b frames 
    p = end_of_pak(m_head);
    while (p != m_head) {
      q = end_of_pak(p->rtp_next);
      if (((q->rtp_pak_seq + 1) & 0xffff) == q->rtp_next->rtp_pak_seq) {
	q = q->rtp_next;
	m_rtp_frame_add  = q->rtp_pak_ts - p->rtp_pak_ts;
	SDL_UnlockMutex(m_rtp_packet_mutex);
	return;
      }
      p = q->rtp_next;
    }
  }

  m_buffering = 0;
  SDL_UnlockMutex(m_rtp_packet_mutex);
  flush_rtp_packets();
}

⌨️ 快捷键说明

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