diff options
-rw-r--r-- | include/media/mediarecorder.h | 3 | ||||
-rw-r--r-- | include/media/stagefright/MPEG2TSWriter.h | 5 | ||||
-rw-r--r-- | media/java/android/media/MediaRecorder.java | 3 | ||||
-rw-r--r-- | media/libmedia/mediarecorder.cpp | 2 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.cpp | 50 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.h | 1 | ||||
-rw-r--r-- | media/libstagefright/MPEG2TSWriter.cpp | 88 |
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> ¬ify) { 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(); |