Merge "Support for MP4V-ES packetization format according to RFC3016." into gingerbread
This commit is contained in:
committed by
Android (Google) Code Review
commit
223e4f732a
166
media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
Normal file
166
media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "AMPEG4ElementaryAssembler.h"
|
||||||
|
|
||||||
|
#include "ARTPSource.h"
|
||||||
|
|
||||||
|
#include <media/stagefright/foundation/ABuffer.h>
|
||||||
|
#include <media/stagefright/foundation/ADebug.h>
|
||||||
|
#include <media/stagefright/foundation/AMessage.h>
|
||||||
|
#include <media/stagefright/foundation/hexdump.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define BE_VERBOSE 0
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
// static
|
||||||
|
AMPEG4ElementaryAssembler::AMPEG4ElementaryAssembler(const sp<AMessage> ¬ify)
|
||||||
|
: mNotifyMsg(notify),
|
||||||
|
mAccessUnitRTPTime(0),
|
||||||
|
mNextExpectedSeqNoValid(false),
|
||||||
|
mNextExpectedSeqNo(0),
|
||||||
|
mAccessUnitDamaged(false) {
|
||||||
|
}
|
||||||
|
|
||||||
|
AMPEG4ElementaryAssembler::~AMPEG4ElementaryAssembler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::addPacket(
|
||||||
|
const sp<ARTPSource> &source) {
|
||||||
|
List<sp<ABuffer> > *queue = source->queue();
|
||||||
|
|
||||||
|
if (queue->empty()) {
|
||||||
|
return NOT_ENOUGH_DATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mNextExpectedSeqNoValid) {
|
||||||
|
List<sp<ABuffer> >::iterator it = queue->begin();
|
||||||
|
while (it != queue->end()) {
|
||||||
|
if ((uint32_t)(*it)->int32Data() >= mNextExpectedSeqNo) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
it = queue->erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (queue->empty()) {
|
||||||
|
return NOT_ENOUGH_DATA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<ABuffer> buffer = *queue->begin();
|
||||||
|
|
||||||
|
if (!mNextExpectedSeqNoValid) {
|
||||||
|
mNextExpectedSeqNoValid = true;
|
||||||
|
mNextExpectedSeqNo = (uint32_t)buffer->int32Data();
|
||||||
|
} else if ((uint32_t)buffer->int32Data() != mNextExpectedSeqNo) {
|
||||||
|
#if BE_VERBOSE
|
||||||
|
LOG(VERBOSE) << "Not the sequence number I expected";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return WRONG_SEQUENCE_NUMBER;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t rtpTime;
|
||||||
|
CHECK(buffer->meta()->findInt32("rtp-time", (int32_t *)&rtpTime));
|
||||||
|
|
||||||
|
if (mPackets.size() > 0 && rtpTime != mAccessUnitRTPTime) {
|
||||||
|
submitAccessUnit();
|
||||||
|
}
|
||||||
|
mAccessUnitRTPTime = rtpTime;
|
||||||
|
|
||||||
|
mPackets.push_back(buffer);
|
||||||
|
// hexdump(buffer->data(), buffer->size());
|
||||||
|
|
||||||
|
queue->erase(queue->begin());
|
||||||
|
++mNextExpectedSeqNo;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AMPEG4ElementaryAssembler::submitAccessUnit() {
|
||||||
|
CHECK(!mPackets.empty());
|
||||||
|
|
||||||
|
#if BE_VERBOSE
|
||||||
|
LOG(VERBOSE) << "Access unit complete (" << mPackets.size() << " nal units)";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint64_t ntpTime;
|
||||||
|
CHECK((*mPackets.begin())->meta()->findInt64(
|
||||||
|
"ntp-time", (int64_t *)&ntpTime));
|
||||||
|
|
||||||
|
size_t totalSize = 0;
|
||||||
|
for (List<sp<ABuffer> >::iterator it = mPackets.begin();
|
||||||
|
it != mPackets.end(); ++it) {
|
||||||
|
totalSize += (*it)->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<ABuffer> accessUnit = new ABuffer(totalSize);
|
||||||
|
size_t offset = 0;
|
||||||
|
for (List<sp<ABuffer> >::iterator it = mPackets.begin();
|
||||||
|
it != mPackets.end(); ++it) {
|
||||||
|
sp<ABuffer> nal = *it;
|
||||||
|
memcpy(accessUnit->data() + offset, nal->data(), nal->size());
|
||||||
|
offset += nal->size();
|
||||||
|
}
|
||||||
|
|
||||||
|
accessUnit->meta()->setInt64("ntp-time", ntpTime);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
printf(mAccessUnitDamaged ? "X" : ".");
|
||||||
|
fflush(stdout);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (mAccessUnitDamaged) {
|
||||||
|
accessUnit->meta()->setInt32("damaged", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
mPackets.clear();
|
||||||
|
mAccessUnitDamaged = false;
|
||||||
|
|
||||||
|
sp<AMessage> msg = mNotifyMsg->dup();
|
||||||
|
msg->setObject("access-unit", accessUnit);
|
||||||
|
msg->post();
|
||||||
|
}
|
||||||
|
|
||||||
|
ARTPAssembler::AssemblyStatus AMPEG4ElementaryAssembler::assembleMore(
|
||||||
|
const sp<ARTPSource> &source) {
|
||||||
|
AssemblyStatus status = addPacket(source);
|
||||||
|
if (status == MALFORMED_PACKET) {
|
||||||
|
mAccessUnitDamaged = true;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AMPEG4ElementaryAssembler::packetLost() {
|
||||||
|
CHECK(mNextExpectedSeqNoValid);
|
||||||
|
LOG(VERBOSE) << "packetLost (expected " << mNextExpectedSeqNo << ")";
|
||||||
|
|
||||||
|
++mNextExpectedSeqNo;
|
||||||
|
|
||||||
|
mAccessUnitDamaged = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AMPEG4ElementaryAssembler::onByeReceived() {
|
||||||
|
sp<AMessage> msg = mNotifyMsg->dup();
|
||||||
|
msg->setInt32("eos", true);
|
||||||
|
msg->post();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
58
media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
Normal file
58
media/libstagefright/rtsp/AMPEG4ElementaryAssembler.h
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef A_MPEG4_ELEM_ASSEMBLER_H_
|
||||||
|
|
||||||
|
#define A_MPEG4_ELEM_ASSEMBLER_H_
|
||||||
|
|
||||||
|
#include "ARTPAssembler.h"
|
||||||
|
|
||||||
|
#include <utils/List.h>
|
||||||
|
#include <utils/RefBase.h>
|
||||||
|
|
||||||
|
namespace android {
|
||||||
|
|
||||||
|
struct ABuffer;
|
||||||
|
struct AMessage;
|
||||||
|
|
||||||
|
struct AMPEG4ElementaryAssembler : public ARTPAssembler {
|
||||||
|
AMPEG4ElementaryAssembler(const sp<AMessage> ¬ify);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual ~AMPEG4ElementaryAssembler();
|
||||||
|
|
||||||
|
virtual AssemblyStatus assembleMore(const sp<ARTPSource> &source);
|
||||||
|
virtual void onByeReceived();
|
||||||
|
virtual void packetLost();
|
||||||
|
|
||||||
|
private:
|
||||||
|
sp<AMessage> mNotifyMsg;
|
||||||
|
|
||||||
|
uint32_t mAccessUnitRTPTime;
|
||||||
|
bool mNextExpectedSeqNoValid;
|
||||||
|
uint32_t mNextExpectedSeqNo;
|
||||||
|
bool mAccessUnitDamaged;
|
||||||
|
List<sp<ABuffer> > mPackets;
|
||||||
|
|
||||||
|
AssemblyStatus addPacket(const sp<ARTPSource> &source);
|
||||||
|
void submitAccessUnit();
|
||||||
|
|
||||||
|
DISALLOW_EVIL_CONSTRUCTORS(AMPEG4ElementaryAssembler);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace android
|
||||||
|
|
||||||
|
#endif // A_MPEG4_ELEM_ASSEMBLER_H_
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include <media/stagefright/foundation/ABitReader.h>
|
||||||
#include <media/stagefright/foundation/ABuffer.h>
|
#include <media/stagefright/foundation/ABuffer.h>
|
||||||
#include <media/stagefright/foundation/ADebug.h>
|
#include <media/stagefright/foundation/ADebug.h>
|
||||||
#include <media/stagefright/foundation/AMessage.h>
|
#include <media/stagefright/foundation/AMessage.h>
|
||||||
@@ -246,6 +247,161 @@ sp<ABuffer> MakeAACCodecSpecificData(const char *params) {
|
|||||||
return csd;
|
return csd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t GetSizeWidth(size_t x) {
|
||||||
|
size_t n = 1;
|
||||||
|
while (x > 127) {
|
||||||
|
++n;
|
||||||
|
x >>= 7;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t *EncodeSize(uint8_t *dst, size_t x) {
|
||||||
|
while (x > 127) {
|
||||||
|
*dst++ = (x & 0x7f) | 0x80;
|
||||||
|
x >>= 7;
|
||||||
|
}
|
||||||
|
*dst++ = x;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ExtractDimensionsFromVOLHeader(
|
||||||
|
const sp<ABuffer> &config, int32_t *width, int32_t *height) {
|
||||||
|
*width = 0;
|
||||||
|
*height = 0;
|
||||||
|
|
||||||
|
const uint8_t *ptr = config->data();
|
||||||
|
size_t offset = 0;
|
||||||
|
bool foundVOL = false;
|
||||||
|
while (offset + 3 < config->size()) {
|
||||||
|
if (memcmp("\x00\x00\x01", &ptr[offset], 3)
|
||||||
|
|| (ptr[offset + 3] & 0xf0) != 0x20) {
|
||||||
|
++offset;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foundVOL = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!foundVOL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ABitReader br(&ptr[offset + 4], config->size() - offset - 4);
|
||||||
|
br.skipBits(1); // random_accessible_vol
|
||||||
|
unsigned video_object_type_indication = br.getBits(8);
|
||||||
|
|
||||||
|
CHECK_NE(video_object_type_indication,
|
||||||
|
0x21u /* Fine Granularity Scalable */);
|
||||||
|
|
||||||
|
unsigned video_object_layer_verid;
|
||||||
|
unsigned video_object_layer_priority;
|
||||||
|
if (br.getBits(1)) {
|
||||||
|
video_object_layer_verid = br.getBits(4);
|
||||||
|
video_object_layer_priority = br.getBits(3);
|
||||||
|
}
|
||||||
|
unsigned aspect_ratio_info = br.getBits(4);
|
||||||
|
if (aspect_ratio_info == 0x0f /* extended PAR */) {
|
||||||
|
br.skipBits(8); // par_width
|
||||||
|
br.skipBits(8); // par_height
|
||||||
|
}
|
||||||
|
if (br.getBits(1)) { // vol_control_parameters
|
||||||
|
br.skipBits(2); // chroma_format
|
||||||
|
br.skipBits(1); // low_delay
|
||||||
|
if (br.getBits(1)) { // vbv_parameters
|
||||||
|
TRESPASS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned video_object_layer_shape = br.getBits(2);
|
||||||
|
CHECK_EQ(video_object_layer_shape, 0x00u /* rectangular */);
|
||||||
|
|
||||||
|
CHECK(br.getBits(1)); // marker_bit
|
||||||
|
unsigned vop_time_increment_resolution = br.getBits(16);
|
||||||
|
CHECK(br.getBits(1)); // marker_bit
|
||||||
|
|
||||||
|
if (br.getBits(1)) { // fixed_vop_rate
|
||||||
|
// range [0..vop_time_increment_resolution)
|
||||||
|
|
||||||
|
// vop_time_increment_resolution
|
||||||
|
// 2 => 0..1, 1 bit
|
||||||
|
// 3 => 0..2, 2 bits
|
||||||
|
// 4 => 0..3, 2 bits
|
||||||
|
// 5 => 0..4, 3 bits
|
||||||
|
// ...
|
||||||
|
|
||||||
|
CHECK_GT(vop_time_increment_resolution, 0u);
|
||||||
|
--vop_time_increment_resolution;
|
||||||
|
|
||||||
|
unsigned numBits = 0;
|
||||||
|
while (vop_time_increment_resolution > 0) {
|
||||||
|
++numBits;
|
||||||
|
vop_time_increment_resolution >>= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
br.skipBits(numBits); // fixed_vop_time_increment
|
||||||
|
}
|
||||||
|
|
||||||
|
CHECK(br.getBits(1)); // marker_bit
|
||||||
|
unsigned video_object_layer_width = br.getBits(13);
|
||||||
|
CHECK(br.getBits(1)); // marker_bit
|
||||||
|
unsigned video_object_layer_height = br.getBits(13);
|
||||||
|
CHECK(br.getBits(1)); // marker_bit
|
||||||
|
|
||||||
|
unsigned interlaced = br.getBits(1);
|
||||||
|
|
||||||
|
*width = video_object_layer_width;
|
||||||
|
*height = video_object_layer_height;
|
||||||
|
|
||||||
|
LOG(INFO) << "VOL dimensions = " << *width << "x" << *height;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
sp<ABuffer> MakeMPEG4VideoCodecSpecificData(
|
||||||
|
const char *params, int32_t *width, int32_t *height) {
|
||||||
|
*width = 0;
|
||||||
|
*height = 0;
|
||||||
|
|
||||||
|
AString val;
|
||||||
|
CHECK(GetAttribute(params, "config", &val));
|
||||||
|
|
||||||
|
sp<ABuffer> config = decodeHex(val);
|
||||||
|
CHECK(config != NULL);
|
||||||
|
|
||||||
|
if (!ExtractDimensionsFromVOLHeader(config, width, height)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len1 = config->size() + GetSizeWidth(config->size()) + 1;
|
||||||
|
size_t len2 = len1 + GetSizeWidth(len1) + 1 + 13;
|
||||||
|
size_t len3 = len2 + GetSizeWidth(len2) + 1 + 3;
|
||||||
|
|
||||||
|
sp<ABuffer> csd = new ABuffer(len3);
|
||||||
|
uint8_t *dst = csd->data();
|
||||||
|
*dst++ = 0x03;
|
||||||
|
dst = EncodeSize(dst, len2 + 3);
|
||||||
|
*dst++ = 0x00; // ES_ID
|
||||||
|
*dst++ = 0x00;
|
||||||
|
*dst++ = 0x00; // streamDependenceFlag, URL_Flag, OCRstreamFlag
|
||||||
|
|
||||||
|
*dst++ = 0x04;
|
||||||
|
dst = EncodeSize(dst, len1 + 13);
|
||||||
|
*dst++ = 0x01; // Video ISO/IEC 14496-2 Simple Profile
|
||||||
|
for (size_t i = 0; i < 12; ++i) {
|
||||||
|
*dst++ = 0x00;
|
||||||
|
}
|
||||||
|
|
||||||
|
*dst++ = 0x05;
|
||||||
|
dst = EncodeSize(dst, config->size());
|
||||||
|
memcpy(dst, config->data(), config->size());
|
||||||
|
dst += config->size();
|
||||||
|
|
||||||
|
// hexdump(csd->data(), csd->size());
|
||||||
|
|
||||||
|
return csd;
|
||||||
|
}
|
||||||
|
|
||||||
APacketSource::APacketSource(
|
APacketSource::APacketSource(
|
||||||
const sp<ASessionDescription> &sessionDesc, size_t index)
|
const sp<ASessionDescription> &sessionDesc, size_t index)
|
||||||
: mInitCheck(NO_INIT),
|
: mInitCheck(NO_INIT),
|
||||||
@@ -351,6 +507,36 @@ APacketSource::APacketSource(
|
|||||||
if (sampleRate != 16000 || numChannels != 1) {
|
if (sampleRate != 16000 || numChannels != 1) {
|
||||||
mInitCheck = ERROR_UNSUPPORTED;
|
mInitCheck = ERROR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
} else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) {
|
||||||
|
mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4);
|
||||||
|
|
||||||
|
int32_t width, height;
|
||||||
|
if (!sessionDesc->getDimensions(index, PT, &width, &height)) {
|
||||||
|
width = -1;
|
||||||
|
height = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t encWidth, encHeight;
|
||||||
|
sp<ABuffer> codecSpecificData =
|
||||||
|
MakeMPEG4VideoCodecSpecificData(
|
||||||
|
params.c_str(), &encWidth, &encHeight);
|
||||||
|
|
||||||
|
if (codecSpecificData != NULL) {
|
||||||
|
mFormat->setData(
|
||||||
|
kKeyESDS, 0,
|
||||||
|
codecSpecificData->data(), codecSpecificData->size());
|
||||||
|
|
||||||
|
if (width < 0) {
|
||||||
|
width = encWidth;
|
||||||
|
height = encHeight;
|
||||||
|
}
|
||||||
|
} else if (width < 0) {
|
||||||
|
mInitCheck = ERROR_UNSUPPORTED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mFormat->setInt32(kKeyWidth, width);
|
||||||
|
mFormat->setInt32(kKeyHeight, height);
|
||||||
} else {
|
} else {
|
||||||
mInitCheck = ERROR_UNSUPPORTED;
|
mInitCheck = ERROR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -321,6 +321,8 @@ status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) {
|
|||||||
|
|
||||||
buffer->setRange(0, nbytes);
|
buffer->setRange(0, nbytes);
|
||||||
|
|
||||||
|
// LOG(INFO) << "received " << buffer->size() << " bytes.";
|
||||||
|
|
||||||
status_t err;
|
status_t err;
|
||||||
if (receiveRTP) {
|
if (receiveRTP) {
|
||||||
err = parseRTP(s, buffer);
|
err = parseRTP(s, buffer);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include "AAVCAssembler.h"
|
#include "AAVCAssembler.h"
|
||||||
#include "AH263Assembler.h"
|
#include "AH263Assembler.h"
|
||||||
#include "AMPEG4AudioAssembler.h"
|
#include "AMPEG4AudioAssembler.h"
|
||||||
|
#include "AMPEG4ElementaryAssembler.h"
|
||||||
#include "ASessionDescription.h"
|
#include "ASessionDescription.h"
|
||||||
|
|
||||||
#include <media/stagefright/foundation/ABuffer.h>
|
#include <media/stagefright/foundation/ABuffer.h>
|
||||||
@@ -63,6 +64,9 @@ ARTPSource::ARTPSource(
|
|||||||
mAssembler = new AAMRAssembler(notify, false /* isWide */, params);
|
mAssembler = new AAMRAssembler(notify, false /* isWide */, params);
|
||||||
} else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
|
} else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
|
||||||
mAssembler = new AAMRAssembler(notify, true /* isWide */, params);
|
mAssembler = new AAMRAssembler(notify, true /* isWide */, params);
|
||||||
|
} else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)) {
|
||||||
|
mAssembler = new AMPEG4ElementaryAssembler(notify);
|
||||||
|
mIssueFIRRequests = true;
|
||||||
} else {
|
} else {
|
||||||
TRESPASS();
|
TRESPASS();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ LOCAL_SRC_FILES:= \
|
|||||||
AAVCAssembler.cpp \
|
AAVCAssembler.cpp \
|
||||||
AH263Assembler.cpp \
|
AH263Assembler.cpp \
|
||||||
AMPEG4AudioAssembler.cpp \
|
AMPEG4AudioAssembler.cpp \
|
||||||
|
AMPEG4ElementaryAssembler.cpp \
|
||||||
APacketSource.cpp \
|
APacketSource.cpp \
|
||||||
ARTPAssembler.cpp \
|
ARTPAssembler.cpp \
|
||||||
ARTPConnection.cpp \
|
ARTPConnection.cpp \
|
||||||
|
|||||||
Reference in New Issue
Block a user