summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/media/mediarecorder.h3
-rw-r--r--include/media/stagefright/MPEG2TSWriter.h5
-rw-r--r--media/java/android/media/MediaRecorder.java3
-rw-r--r--media/libmedia/mediarecorder.cpp2
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp50
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h1
-rw-r--r--media/libstagefright/MPEG2TSWriter.cpp88
7 files changed, 131 insertions, 21 deletions
diff --git a/include/media/mediarecorder.h b/include/media/mediarecorder.h
index 291b18a..5ab1640 100644
--- a/include/media/mediarecorder.h
+++ b/include/media/mediarecorder.h
@@ -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
};
diff --git a/include/media/stagefright/MPEG2TSWriter.h b/include/media/stagefright/MPEG2TSWriter.h
index 551ca01..f2c6505 100644
--- a/include/media/stagefright/MPEG2TSWriter.h
+++ b/include/media/stagefright/MPEG2TSWriter.h
@@ -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();
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 34a86ec..b38124e 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -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;
};
/**
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 9d53c25..e20e3ba 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -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;
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index cf01ff6..d37d83d 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -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(
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index 216f6bc..ad0dfa0 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -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);
diff --git a/media/libstagefright/MPEG2TSWriter.cpp b/media/libstagefright/MPEG2TSWriter.cpp
index ee74b88..b3daf67 100644
--- a/media/libstagefright/MPEG2TSWriter.cpp
+++ b/media/libstagefright/MPEG2TSWriter.cpp
@@ -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,17 +137,47 @@ void MPEG2TSWriter::SourceInfo::extractCodecSpecificData() {
const char *mime;
CHECK(meta->findCString(kKeyMIMEType, &mime));
- if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ 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;
}
- sp<ABuffer> out = new ABuffer(1024);
- out->setRange(0, 0);
+ if (strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
+ return;
+ }
uint32_t type;
const void *data;
size_t size;
- CHECK(meta->findData(kKeyAVCC, &type, &data, &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);
const uint8_t *ptr = (const uint8_t *)data;
@@ -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();