Merge "Support for writing to MPEG2 transport stream files." into gingerbread

This commit is contained in:
Andreas Huber
2010-10-13 09:14:40 -07:00
committed by Android (Google) Code Review
7 changed files with 132 additions and 22 deletions

View File

@@ -76,6 +76,9 @@ enum output_format {
/* Stream over a socket, limited to a single stream */
OUTPUT_FORMAT_RTP_AVP = 7,
/* H.264/AAC data encapsulated in MPEG2/TS */
OUTPUT_FORMAT_MPEG2TS = 8,
OUTPUT_FORMAT_LIST_END // must be last - used to validate format type
};

View File

@@ -25,7 +25,10 @@
namespace android {
struct ABuffer;
struct MPEG2TSWriter : public MediaWriter {
MPEG2TSWriter(int fd);
MPEG2TSWriter(const char *filename);
virtual status_t addSource(const sp<MediaSource> &source);
@@ -59,6 +62,8 @@ private:
int64_t mNumTSPacketsWritten;
int64_t mNumTSPacketsBeforeMeta;
void init();
void writeTS();
void writeProgramAssociationTable();
void writeProgramMap();

View File

@@ -191,6 +191,9 @@ public class MediaRecorder
/** @hide Stream over a socket, limited to a single stream */
public static final int OUTPUT_FORMAT_RTP_AVP = 7;
/** @hide H.264/AAC data encapsulated in MPEG2/TS */
public static final int OUTPUT_FORMAT_MPEG2TS = 8;
};
/**

View File

@@ -181,7 +181,7 @@ status_t MediaRecorder::setOutputFormat(int of)
LOGE("setOutputFormat called in an invalid state: %d", mCurrentState);
return INVALID_OPERATION;
}
if (mIsVideoSourceSet && of >= OUTPUT_FORMAT_AUDIO_ONLY_START && of != OUTPUT_FORMAT_RTP_AVP) { //first non-video output format
if (mIsVideoSourceSet && of >= OUTPUT_FORMAT_AUDIO_ONLY_START && of != OUTPUT_FORMAT_RTP_AVP && of != OUTPUT_FORMAT_MPEG2TS) { //first non-video output format
LOGE("output format (%d) is meant for audio recording only and incompatible with video recording", of);
return INVALID_OPERATION;
}

View File

@@ -24,6 +24,7 @@
#include <media/stagefright/AudioSource.h>
#include <media/stagefright/AMRWriter.h>
#include <media/stagefright/CameraSource.h>
#include <media/stagefright/MPEG2TSWriter.h>
#include <media/stagefright/MPEG4Writer.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
@@ -632,6 +633,9 @@ status_t StagefrightRecorder::start() {
case OUTPUT_FORMAT_RTP_AVP:
return startRTPRecording();
case OUTPUT_FORMAT_MPEG2TS:
return startMPEG2TSRecording();
default:
LOGE("Unsupported output file format: %d", mOutputFormat);
return UNKNOWN_ERROR;
@@ -799,6 +803,52 @@ status_t StagefrightRecorder::startRTPRecording() {
return mWriter->start();
}
status_t StagefrightRecorder::startMPEG2TSRecording() {
CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_MPEG2TS);
sp<MediaWriter> writer = new MPEG2TSWriter(dup(mOutputFd));
if (mAudioSource != AUDIO_SOURCE_LIST_END) {
if (mAudioEncoder != AUDIO_ENCODER_AAC) {
return ERROR_UNSUPPORTED;
}
status_t err = setupAudioEncoder(writer);
if (err != OK) {
return err;
}
}
if (mVideoSource == VIDEO_SOURCE_DEFAULT
|| mVideoSource == VIDEO_SOURCE_CAMERA) {
if (mVideoEncoder != VIDEO_ENCODER_H264) {
return ERROR_UNSUPPORTED;
}
sp<MediaSource> encoder;
status_t err = setupVideoEncoder(&encoder);
if (err != OK) {
return err;
}
writer->addSource(encoder);
}
if (mMaxFileDurationUs != 0) {
writer->setMaxFileDuration(mMaxFileDurationUs);
}
if (mMaxFileSizeBytes != 0) {
writer->setMaxFileSize(mMaxFileSizeBytes);
}
mWriter = writer;
return mWriter->start();
}
void StagefrightRecorder::clipVideoFrameRate() {
LOGV("clipVideoFrameRate: encoder %d", mVideoEncoder);
int minFrameRate = mEncoderProfiles->getVideoEncoderParamByName(

View File

@@ -102,6 +102,7 @@ private:
status_t startAMRRecording();
status_t startAACRecording();
status_t startRTPRecording();
status_t startMPEG2TSRecording();
sp<MediaSource> createAudioSource();
status_t setupCameraSource();
status_t setupAudioEncoder(const sp<MediaWriter>& writer);

View File

@@ -63,6 +63,8 @@ private:
sp<ALooper> mLooper;
sp<AMessage> mNotify;
sp<ABuffer> mAACCodecSpecificData;
sp<ABuffer> mAACBuffer;
unsigned mStreamType;
@@ -125,6 +127,8 @@ void MPEG2TSWriter::SourceInfo::start(const sp<AMessage> &notify) {
void MPEG2TSWriter::SourceInfo::stop() {
mLooper->unregisterHandler(id());
mLooper->stop();
mSource->stop();
}
void MPEG2TSWriter::SourceInfo::extractCodecSpecificData() {
@@ -133,18 +137,48 @@ void MPEG2TSWriter::SourceInfo::extractCodecSpecificData() {
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
uint32_t type;
const void *data;
size_t size;
if (!meta->findData(kKeyESDS, &type, &data, &size)) {
// Codec specific data better be in the first data buffer.
return;
}
ESDS esds((const char *)data, size);
CHECK_EQ(esds.InitCheck(), (status_t)OK);
const uint8_t *codec_specific_data;
size_t codec_specific_data_size;
esds.getCodecSpecificInfo(
(const void **)&codec_specific_data, &codec_specific_data_size);
CHECK_GE(codec_specific_data_size, 2u);
mAACCodecSpecificData = new ABuffer(codec_specific_data_size);
memcpy(mAACCodecSpecificData->data(), codec_specific_data,
codec_specific_data_size);
return;
}
if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
return;
}
uint32_t type;
const void *data;
size_t size;
if (!meta->findData(kKeyAVCC, &type, &data, &size)) {
// Codec specific data better be part of the data stream then.
return;
}
sp<ABuffer> out = new ABuffer(1024);
out->setRange(0, 0);
uint32_t type;
const void *data;
size_t size;
CHECK(meta->findData(kKeyAVCC, &type, &data, &size));
const uint8_t *ptr = (const uint8_t *)data;
size_t numSeqParameterSets = ptr[5] & 31;
@@ -250,21 +284,7 @@ void MPEG2TSWriter::SourceInfo::appendAACFrames(MediaBuffer *buffer) {
mAACBuffer->setRange(0, 0);
}
sp<MetaData> meta = mSource->getFormat();
uint32_t type;
const void *data;
size_t size;
CHECK(meta->findData(kKeyESDS, &type, &data, &size));
ESDS esds((const char *)data, size);
CHECK_EQ(esds.InitCheck(), (status_t)OK);
const uint8_t *codec_specific_data;
size_t codec_specific_data_size;
esds.getCodecSpecificInfo(
(const void **)&codec_specific_data, &codec_specific_data_size);
CHECK_GE(codec_specific_data_size, 2u);
const uint8_t *codec_specific_data = mAACCodecSpecificData->data();
unsigned profile = (codec_specific_data[0] >> 3) - 1;
@@ -355,7 +375,18 @@ void MPEG2TSWriter::SourceInfo::onMessageReceived(const sp<AMessage> &msg) {
}
if (err == OK) {
if (buffer->range_length() > 0) {
if (mStreamType == 0x0f && mAACCodecSpecificData == NULL) {
// The first buffer contains codec specific data.
CHECK_GE(buffer->range_length(), 2u);
mAACCodecSpecificData = new ABuffer(buffer->range_length());
memcpy(mAACCodecSpecificData->data(),
(const uint8_t *)buffer->data()
+ buffer->range_offset(),
buffer->range_length());
} else if (buffer->range_length() > 0) {
if (mStreamType == 0x0f) {
appendAACFrames(buffer);
} else {
@@ -378,12 +409,25 @@ void MPEG2TSWriter::SourceInfo::onMessageReceived(const sp<AMessage> &msg) {
////////////////////////////////////////////////////////////////////////////////
MPEG2TSWriter::MPEG2TSWriter(int fd)
: mFile(fdopen(fd, "wb")),
mStarted(false),
mNumSourcesDone(0),
mNumTSPacketsWritten(0),
mNumTSPacketsBeforeMeta(0) {
init();
}
MPEG2TSWriter::MPEG2TSWriter(const char *filename)
: mFile(fopen(filename, "wb")),
mStarted(false),
mNumSourcesDone(0),
mNumTSPacketsWritten(0),
mNumTSPacketsBeforeMeta(0) {
init();
}
void MPEG2TSWriter::init() {
CHECK(mFile != NULL);
mLooper = new ALooper;
@@ -396,6 +440,10 @@ MPEG2TSWriter::MPEG2TSWriter(const char *filename)
}
MPEG2TSWriter::~MPEG2TSWriter() {
if (mStarted) {
stop();
}
mLooper->unregisterHandler(mReflector->id());
mLooper->stop();