📄 rfc3119_bytestream.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. 2002. All Rights Reserved.
*
* Contributor(s):
* Bill May wmay@cisco.com
*/
/*
* rfc3119_bytestream.cpp - an implemention of rfc 3119
*/
#include "systems.h"
#include <rtp/rtp.h>
#include <rtp/memory.h>
#include <sdp/sdp.h> // for NTP_TO_UNIX_TIME
#include "rfc3119_bytestream.h"
#include <mp3util/MP3Internals.hh>
//#define DEBUG_3119 1
//#define DEBUG_3119_INTERLEAVE 1
#ifdef _WIN32
DEFINE_MESSAGE_MACRO(mpa_message, "mparobust")
#else
#define mpa_message(loglevel, fmt...) message(loglevel, "mparobust", fmt)
#endif
CRfc3119RtpByteStream::CRfc3119RtpByteStream (unsigned int rtp_pt,
format_list_t *fmt,
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("mparobust", 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_adu_data_free = NULL;
m_deinterleave_list = NULL;
m_ordered_adu_list = NULL;
m_pending_adu_list = NULL;
adu_data_t *p;
for (int ix = 0; ix < 25; ix++) {
p = MALLOC_STRUCTURE(adu_data_t);
p->next_adu = m_adu_data_free;
m_adu_data_free = p;
}
m_rtp_ts_add = 0;
m_recvd_first_pak = 0;
m_got_next_idx = 0;
m_mp3_frame = NULL;
m_mp3_frame_size = 0;
}
CRfc3119RtpByteStream::~CRfc3119RtpByteStream (void)
{
#ifdef ISMA_RTP_DUMP_OUTPUT_TO_FILE
fclose(m_outfile);
#endif
adu_data_t *p;
#if 0
if (m_frag_reass_buffer != NULL) {
free(m_frag_reass_buffer);
m_frag_reass_buffer = NULL;
}
#endif
dump_adu_list(m_deinterleave_list);
m_deinterleave_list = NULL;
dump_adu_list(m_ordered_adu_list);
m_ordered_adu_list = NULL;
dump_adu_list(m_pending_adu_list);
m_pending_adu_list = NULL;
while (m_adu_data_free != NULL) {
p = m_adu_data_free;
m_adu_data_free = p->next_adu;
free(p);
}
}
void CRfc3119RtpByteStream::insert_interleave_adu (adu_data_t *adu)
{
adu_data_t *p, *q;
#ifdef DEBUG_3119_INTERLEAVE
mpa_message(LOG_DEBUG, "inserting interleave %d %d %d", adu->aduDataSize,
adu->cyc_ct, adu->interleave_idx);
#endif
SDL_LockMutex(m_rtp_packet_mutex);
if (m_deinterleave_list == NULL) {
m_got_next_idx = 0;
m_deinterleave_list = adu;
} else {
q = NULL;
p = m_deinterleave_list;
if (adu->cyc_ct != p->cyc_ct) {
m_got_next_idx = 1;
do {
q = p;
p = p->next_adu;
} while (p != NULL && p->cyc_ct != adu->cyc_ct);
if (p == NULL) {
q->next_adu = adu;
SDL_UnlockMutex(m_rtp_packet_mutex);
return;
}
}
while (p != NULL && p->interleave_idx < adu->interleave_idx) {
q = p;
p = p->next_adu;
}
q->next_adu = adu;
adu->next_adu = p;
}
SDL_UnlockMutex(m_rtp_packet_mutex);
}
int CRfc3119RtpByteStream::insert_processed_adu (adu_data_t *adu)
{
#ifdef DEBUG_3119
mpa_message(LOG_DEBUG, "inserting processed %d", adu->aduDataSize);
#endif
SDL_LockMutex(m_rtp_packet_mutex);
if (m_ordered_adu_list == NULL) {
m_ordered_adu_list = adu;
} else {
int32_t diff;
adu_data_t *p, *q;
q = NULL;
p = m_ordered_adu_list;
do {
diff = adu->timestamp - p->timestamp;
if (diff == 0) {
mpa_message(LOG_ERR, "Duplicate timestamp of "LLU" found in RTP packet",
adu->timestamp);
mpa_message(LOG_DEBUG,
"Seq number orig %d new %d",
p->pak->rtp_pak_seq, adu->pak->rtp_pak_seq);
mpa_message(LOG_ERR, "Dumping all processed packets");
// put frame_data on free list
if (adu->last_in_pak == 0) {
free_adu(adu);
} else {
mpa_message(LOG_ERR, "Im lazy - duplicate ADU leads to memory leak");
}
SDL_UnlockMutex(m_rtp_packet_mutex);
return -1;
} else if (diff < 0) {
#ifdef DEBUG_3119
mpa_message(LOG_DEBUG, "Inserting in front of ts %llu", p->timestamp);
#endif
if (q == NULL) {
adu->next_adu = m_ordered_adu_list;
m_ordered_adu_list = adu;
} else {
q->next_adu = adu;
adu->next_adu = p;
}
SDL_UnlockMutex(m_rtp_packet_mutex);
return 0;
}
q = p;
p = p->next_adu;
} while (p != NULL);
// insert at end;
q->next_adu = adu;
}
SDL_UnlockMutex(m_rtp_packet_mutex);
return 0;
}
void CRfc3119RtpByteStream::process_packet (void)
{
rtp_packet *pak;
uint64_t pak_ts;
int adu_offset;
adu_data_t *prev_adu;
int thisAduSize;
do {
/*
* Take packet off list. Loop through, looking for ADU headersize
* packets
*/
pak = m_head;
if (pak != NULL) {
remove_packet_rtp_queue(m_head, 0);
pak_ts = rtp_ts_to_msec(pak->rtp_pak_ts, m_wrap_offset);
adu_offset = 0;
prev_adu = NULL;
#ifdef DEBUG_3119
mpa_message(LOG_DEBUG, "Process pak seq %d", pak->rtp_pak_seq);
#endif
while (pak != NULL && adu_offset < pak->rtp_data_len) {
uint8_t *ptr;
ptr = (uint8_t *)(pak->rtp_data + adu_offset);
if ((*ptr & 0x80) == 0x80) {
// first one has a c field of 1 - that's bad
xfree(pak);
pak = NULL;
adu_offset = 0;
} else {
/*
* Get a new adu - start loading the data
*/
adu_data_t *adu = get_adu_data();
adu->pak = pak;
adu->next_adu = NULL;
adu->last_in_pak = 0;
adu->freeframe = 0;
if (adu_offset == 0) {
adu->first_in_pak = 1;
adu->timestamp = pak_ts;
} else {
adu->first_in_pak = 0;
}
/*
* Read the ADU header. It will be 1 byte or 2
*/
if ((*ptr & 0x40) == 0) {
// 1 byte header
adu->frame_ptr = ptr + 1;
adu->aduDataSize = *ptr & 0x3f;
adu_offset++;
} else {
// 2 byte header
adu->aduDataSize = ((*ptr & 0x3f) << 8) + ptr[1];
adu->frame_ptr = ptr + 2;
adu_offset += 2;
}
/*
* See if we're past the end of the packet
*/
thisAduSize = adu->aduDataSize;
if (adu_offset + adu->aduDataSize > pak->rtp_data_len) {
// have a fragment here...
// malloc a frame pointer, and copy the rest...
uint16_t seq = pak->rtp_pak_seq;
uint8_t *to, *from;
to = (uint8_t *)malloc(adu->aduDataSize);
int copied = pak->rtp_data_len - adu_offset;
memcpy(to, adu->frame_ptr, copied);
if (prev_adu != NULL) {
prev_adu->last_in_pak = 1;
} else {
xfree(pak);
}
adu->frame_ptr = to;
adu->freeframe = 1;
to += copied;
while (m_head != NULL &&
m_head->rtp_pak_seq == seq + 1 &&
(*m_head->rtp_data & 0x80) == 0x80 &&
copied < adu->aduDataSize) {
uint32_t bytes;
pak = m_head;
remove_packet_rtp_queue(m_head, 0);
ptr = (uint8_t *)pak->rtp_data;
if ((*ptr & 0x40) == 0) {
// 1 byte header
bytes = *ptr & 0x3f;
from = ptr++;
} else {
// 2 byte header
bytes = ((*ptr & 0x3f) << 8) + ptr[1];
from = ptr + 2;
}
memcpy(to, from, bytes);
copied += bytes;
to += bytes;
seq++;
adu_offset = 0;
pak = NULL;
}
if (copied < adu->aduDataSize) {
free_adu(adu);
continue;
}
} else {
/*
* adu_offset now points past the end of this adu
*/
adu_offset += adu->aduDataSize;
if (adu_offset >= pak->rtp_data_len) {
adu->last_in_pak = 1;
}
}
/*
* Calculate the interleave index and the cyc_ct count
* Fill in those values with all 1's
*/
adu->interleave_idx = *adu->frame_ptr;
adu->cyc_ct = *(adu->frame_ptr + 1) >> 5;
adu->frame_ptr[0] = 0xff;
adu->frame_ptr[1] |= 0xe0;
/*
* Decode the mp3 header
*/
adu->mp3hdr = MP4AV_Mp3HeaderFromBytes(adu->frame_ptr);
adu->framesize = MP4AV_Mp3GetFrameSize(adu->mp3hdr);
/*
* Headersize, sideInfoSize and aduDataSize
*/
adu->headerSize = 4;
adu->sideInfoSize = MP4AV_Mp3GetSideInfoSize(adu->mp3hdr);
adu->aduDataSize -= (adu->headerSize + adu->sideInfoSize);
/*
* Calculate the timestamp add
*/
if (m_rtp_ts_add == 0) {
m_rtp_ts_add =
( 1000 * MP4AV_Mp3GetHdrSamplingWindow(adu->mp3hdr));
m_rtp_ts_add /= MP4AV_Mp3GetHdrSamplingRate(adu->mp3hdr);
}
// here we make a few decisions as to where the packet should
// go.
// Look at first packet. If it's got interleave, we're interleaved
// if not, set up the timestamp, put it in the ordered_adu_list.
// (Don't set recvd_first pak). If it's the 2nd, and not interleaved,
// leave the first, go on non-interleaved
// If the first isn't, and the 2nd is, move the first to the
// m_deinterleave_list, put the 2nd on the deinterleave list,
// continue.
// If not the first, put on the interleaved or deinterleaved list.
int insert_interleaved = 0;
if (m_recvd_first_pak == 0) {
if (adu->interleave_idx == 0xff &&
adu->cyc_ct == 0x7) {
/*
* Have an packet all 1's. It's either the last of the
* sequence for interleave, or indicates no interleave.
* Put it on the ordered list if there's nothing there.
* If there is something on the ordered list, we're not doing
* interleaved.
*/
if (m_ordered_adu_list == NULL) {
insert_interleaved = 0;
} else {
// this is the 2nd packet with the regular
// header - we're not doing interleaved
insert_interleaved = 0;
m_recvd_first_pak = 1;
m_have_interleave = 0;
}
} else {
/*
* Have an interleaved packet
* If there was something on the ordered list, move it to
* the deinterleaved list
*/
m_recvd_first_pak = 1;
if (m_ordered_adu_list != NULL) {
m_deinterleave_list = m_ordered_adu_list;
m_ordered_adu_list = NULL;
}
m_have_interleave = 1;
insert_interleaved = 1;
mpa_message(LOG_INFO, "mpa robust format is interleaved");
}
} else {
insert_interleaved = m_have_interleave;
}
adu->backpointer = MP4AV_Mp3GetAduOffset(adu->frame_ptr,
thisAduSize);
if (insert_interleaved) {
insert_interleave_adu(adu);
} else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -