summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authorLubin Yin <lubiny@codeaurora.org>2015-07-29 12:31:09 +0800
committerSatish Kamuju <skamuj@codeaurora.org>2015-10-06 17:33:49 +0530
commitae614d22fd87feb1857e8041978ab2c38cfaa16e (patch)
treeb6fe7142b7c1dbfcba5250f3fa36991da61a0f33 /media
parent9079a349be70e7c7a5fa8e5bf98be22eeb054db7 (diff)
downloadframeworks_av-ae614d22fd87feb1857e8041978ab2c38cfaa16e.zip
frameworks_av-ae614d22fd87feb1857e8041978ab2c38cfaa16e.tar.gz
frameworks_av-ae614d22fd87feb1857e8041978ab2c38cfaa16e.tar.bz2
libstagefright: MPEG4Writer: Add support for HEVC muxing
Changes done to enable HEVC muxing - writing HVCC atom - configure HEVC encoder Fix HEVC flag initialization Check for HEVC for single track usecase Change-Id: I1757d0c442e7cc3ef251431f220395131a1eb4ec
Diffstat (limited to 'media')
-rw-r--r--media/libavextensions/stagefright/AVExtensions.h38
-rw-r--r--media/libavextensions/stagefright/AVUtils.cpp34
-rw-r--r--media/libmedia/MediaProfiles.cpp3
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.cpp8
-rw-r--r--media/libmediaplayerservice/StagefrightRecorder.h5
-rw-r--r--media/libstagefright/MPEG4Writer.cpp48
-rw-r--r--media/libstagefright/Utils.cpp2
7 files changed, 128 insertions, 10 deletions
diff --git a/media/libavextensions/stagefright/AVExtensions.h b/media/libavextensions/stagefright/AVExtensions.h
index ab0f180..3e51463 100644
--- a/media/libavextensions/stagefright/AVExtensions.h
+++ b/media/libavextensions/stagefright/AVExtensions.h
@@ -38,6 +38,8 @@ namespace android {
class AudioParameter;
class MetaData;
class MediaExtractor;
+class MPEG4Writer;
+struct ABuffer;
struct ACodec;
struct ALooper;
struct IMediaHTTPConnection;
@@ -106,6 +108,42 @@ struct AVUtils {
List<int64_t> &/*decodeTimeQueue*/) {}
virtual bool useQCHWEncoder(const sp<AMessage> &, AString &) { return false; }
+
+ struct HEVCMuxer {
+
+ virtual bool reassembleHEVCCSD(const AString &mime, sp<ABuffer> csd0, sp<MetaData> &meta);
+
+ virtual void writeHEVCFtypBox(MPEG4Writer *writer);
+
+ virtual status_t makeHEVCCodecSpecificData(const uint8_t *data,
+ size_t size, void** codecSpecificData,
+ size_t *codecSpecificDataSize);
+
+ virtual const char *getFourCCForMime(const char *mime);
+
+ virtual void writeHvccBox(MPEG4Writer *writer,
+ void* codecSpecificData, size_t codecSpecificDataSize,
+ bool useNalLengthFour);
+
+ virtual bool isVideoHEVC(const char* mime);
+
+ virtual void getHEVCCodecSpecificDataFromInputFormatIfPossible(
+ sp<MetaData> meta, void **codecSpecificData,
+ size_t *codecSpecificDataSize, bool *gotAllCodecSpecificData);
+
+ protected:
+ HEVCMuxer() {};
+ virtual ~HEVCMuxer() {};
+ friend struct AVUtils;
+ };
+
+ virtual inline HEVCMuxer& HEVCMuxerUtils() {
+ return mHEVCMuxer;
+ }
+
+private:
+ HEVCMuxer mHEVCMuxer;
+
// ----- NO TRESSPASSING BEYOND THIS LINE ------
DECLARE_LOADABLE_SINGLETON(AVUtils);
};
diff --git a/media/libavextensions/stagefright/AVUtils.cpp b/media/libavextensions/stagefright/AVUtils.cpp
index a683f48..8e7c39d 100644
--- a/media/libavextensions/stagefright/AVUtils.cpp
+++ b/media/libavextensions/stagefright/AVUtils.cpp
@@ -109,6 +109,40 @@ bool AVUtils::isEnhancedExtension(const char *) {
return false;
}
+bool AVUtils::HEVCMuxer::reassembleHEVCCSD(const AString &/*mime*/, sp<ABuffer> /*csd0*/, sp<MetaData> &/*meta*/) {
+ return false;
+}
+
+void AVUtils::HEVCMuxer::writeHEVCFtypBox(MPEG4Writer * /*writer*/) {
+ return;
+}
+
+status_t AVUtils::HEVCMuxer::makeHEVCCodecSpecificData(const uint8_t * /*data*/,
+ size_t /*size*/, void ** /*codecSpecificData*/,
+ size_t * /*codecSpecificDataSize*/) {
+ return UNKNOWN_ERROR;
+}
+
+const char *AVUtils::HEVCMuxer::getFourCCForMime(const char * /*mime*/) {
+ return NULL;
+}
+
+void AVUtils::HEVCMuxer::writeHvccBox(MPEG4Writer * /*writer*/,
+ void * /*codecSpecificData*/, size_t /*codecSpecificDataSize*/,
+ bool /*useNalLengthFour*/) {
+ return;
+}
+
+bool AVUtils::HEVCMuxer::isVideoHEVC(const char * /*mime*/) {
+ return false;
+}
+
+void AVUtils::HEVCMuxer::getHEVCCodecSpecificDataFromInputFormatIfPossible(
+ sp<MetaData> /*meta*/, void ** /*codecSpecificData*/,
+ size_t * /*codecSpecificDataSize*/, bool * /*gotAllCodecSpecificData*/) {
+ return;
+}
+
// ----- NO TRESSPASSING BEYOND THIS LINE ------
AVUtils::AVUtils() {}
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index f993950..8af0ce8 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -37,7 +37,8 @@ MediaProfiles *MediaProfiles::sInstance = NULL;
const MediaProfiles::NameToTagMap MediaProfiles::sVideoEncoderNameMap[] = {
{"h263", VIDEO_ENCODER_H263},
{"h264", VIDEO_ENCODER_H264},
- {"m4v", VIDEO_ENCODER_MPEG_4_SP}
+ {"m4v", VIDEO_ENCODER_MPEG_4_SP},
+ {"h265", VIDEO_ENCODER_H265}
};
const MediaProfiles::NameToTagMap MediaProfiles::sAudioEncoderNameMap[] = {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index f261d44..3b4d0eb 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -1501,6 +1501,11 @@ status_t StagefrightRecorder::setupCameraSource(
return OK;
}
+bool StagefrightRecorder::setCustomVideoEncoderMime(const video_encoder /*videoEncoder*/,
+ sp<AMessage> /*format*/) {
+ return false;
+}
+
status_t StagefrightRecorder::setupVideoEncoder(
sp<MediaSource> cameraSource,
sp<MediaSource> *source) {
@@ -1526,6 +1531,9 @@ status_t StagefrightRecorder::setupVideoEncoder(
break;
default:
+ if (setCustomVideoEncoderMime(mVideoEncoder, format)) {
+ break;
+ }
CHECK(!"Should not be here, unsupported video encoding.");
break;
}
diff --git a/media/libmediaplayerservice/StagefrightRecorder.h b/media/libmediaplayerservice/StagefrightRecorder.h
index e7b9e55..bd09d3a 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.h
+++ b/media/libmediaplayerservice/StagefrightRecorder.h
@@ -141,7 +141,7 @@ protected:
status_t setupRTPRecording();
status_t setupMPEG2TSRecording();
sp<MediaSource> createAudioSource();
- status_t checkVideoEncoderCapabilities();
+ virtual status_t checkVideoEncoderCapabilities();
status_t checkAudioEncoderCapabilities();
// Generic MediaSource set-up. Returns the appropriate
// source (CameraSource or SurfaceMediaSource)
@@ -152,6 +152,7 @@ protected:
status_t setupVideoEncoder(sp<MediaSource> cameraSource, sp<MediaSource> *source);
virtual void setupCustomVideoEncoderParams(sp<MediaSource> /*cameraSource*/,
sp<AMessage> &/*format*/) {}
+ virtual bool setCustomVideoEncoderMime(const video_encoder videoEncoder, sp<AMessage> format);
// Encoding parameter handling utilities
status_t setParameter(const String8 &key, const String8 &value);
@@ -184,7 +185,7 @@ protected:
void clipAudioSampleRate();
void clipNumberOfAudioChannels();
void setDefaultProfileIfNecessary();
- void setDefaultVideoEncoderIfNecessary();
+ virtual void setDefaultVideoEncoderIfNecessary();
StagefrightRecorder(const StagefrightRecorder &);
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 8af2615..86ca2a1 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -38,6 +38,7 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/Utils.h>
#include <media/mediarecorder.h>
+#include <stagefright/AVExtensions.h>
#include <cutils/properties.h>
#include "include/ESDS.h"
@@ -91,6 +92,7 @@ public:
bool isAvc() const { return mIsAvc; }
bool isAudio() const { return mIsAudio; }
bool isMPEG4() const { return mIsMPEG4; }
+ bool isHEVC() const { return mIsHEVC; }
void addChunkOffset(off64_t offset);
int32_t getTrackId() const { return mTrackId; }
status_t dump(int fd, const Vector<String16>& args) const;
@@ -236,6 +238,7 @@ private:
bool mIsAvc;
bool mIsAudio;
bool mIsMPEG4;
+ bool mIsHEVC;
int32_t mTrackId;
int64_t mTrackDurationUs;
int64_t mMaxChunkDurationUs;
@@ -386,6 +389,7 @@ MPEG4Writer::MPEG4Writer(int fd)
mAreGeoTagsAvailable(false),
mStartTimeOffsetMs(-1),
mMetaKeys(new AMessage()),
+ mIsVideoHEVC(false),
mIsAudioAMR(false) {
addDeviceMeta();
@@ -464,6 +468,8 @@ const char *MPEG4Writer::Track::getFourCCForMime(const char *mime) {
return "s263";
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
return "avc1";
+ } else {
+ return AVUtils::get()->HEVCMuxerUtils().getFourCCForMime(mime);
}
} else {
ALOGE("Track (%s) other than video or audio is not supported", mime);
@@ -489,6 +495,7 @@ status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
const char *mime;
source->getFormat()->findCString(kKeyMIMEType, &mime);
bool isAudio = !strncasecmp(mime, "audio/", 6);
+ bool isVideo = !strncasecmp(mime, "video/", 6);
if (Track::getFourCCForMime(mime) == NULL) {
ALOGE("Unsupported mime '%s'", mime);
return ERROR_UNSUPPORTED;
@@ -497,6 +504,10 @@ status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
!strcasecmp(MEDIA_MIMETYPE_AUDIO_AMR_WB, mime));
+ if (isVideo) {
+ mIsVideoHEVC = AVUtils::get()->HEVCMuxerUtils().isVideoHEVC(mime);
+ }
+
// At this point, we know the track to be added is either
// video or audio. Thus, we only need to check whether it
// is an audio track or not (if it is not, then it must be
@@ -1051,7 +1062,9 @@ void MPEG4Writer::writeFtypBox(MetaData *param) {
beginBox("ftyp");
int32_t fileType;
- if (mIsAudioAMR || (param && param->findInt32(kKeyFileType, &fileType) &&
+ if (mIsVideoHEVC) {
+ AVUtils::get()->HEVCMuxerUtils().writeHEVCFtypBox(this);
+ } else if (mIsAudioAMR || (param && param->findInt32(kKeyFileType, &fileType) &&
fileType != OUTPUT_FORMAT_MPEG_4)) {
writeFourcc("3gp4");
writeInt32(0);
@@ -1468,6 +1481,12 @@ MPEG4Writer::Track::Track(
mIsAudio = !strncasecmp(mime, "audio/", 6);
mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);
+ mIsHEVC = AVUtils::get()->HEVCMuxerUtils().isVideoHEVC(mime);
+
+ if (mIsHEVC) {
+ AVUtils::get()->HEVCMuxerUtils().getHEVCCodecSpecificDataFromInputFormatIfPossible(
+ mMeta, &mCodecSpecificData, &mCodecSpecificDataSize, &mGotAllCodecSpecificData);
+ }
setTimeScale();
}
@@ -1663,7 +1682,7 @@ void MPEG4Writer::writeChunkToFile(Chunk* chunk) {
while (!chunk->mSamples.empty()) {
List<MediaBuffer *>::iterator it = chunk->mSamples.begin();
- off64_t offset = chunk->mTrack->isAvc()
+ off64_t offset = (chunk->mTrack->isAvc() || chunk->mTrack->isHEVC())
? addLengthPrefixedSample_l(*it)
: addSample_l(*it);
@@ -2244,6 +2263,13 @@ status_t MPEG4Writer::Track::threadEntry() {
(const uint8_t *)buffer->data()
+ buffer->range_offset(),
buffer->range_length());
+ } else if (mIsHEVC) {
+ status_t err = AVUtils::get()->HEVCMuxerUtils().makeHEVCCodecSpecificData(
+ (const uint8_t *)buffer->data() + buffer->range_offset(),
+ buffer->range_length(), &mCodecSpecificData, &mCodecSpecificDataSize);
+ if ((status_t)OK != err) {
+ return err;
+ }
}
buffer->release();
@@ -2263,10 +2289,10 @@ status_t MPEG4Writer::Track::threadEntry() {
buffer->release();
buffer = NULL;
- if (mIsAvc) StripStartcode(copy);
+ if (mIsAvc || mIsHEVC) StripStartcode(copy);
size_t sampleSize = copy->range_length();
- if (mIsAvc) {
+ if (mIsAvc || mIsHEVC) {
if (mOwner->useNalLengthFour()) {
sampleSize += 4;
} else {
@@ -2466,7 +2492,7 @@ status_t MPEG4Writer::Track::threadEntry() {
trackProgressStatus(timestampUs);
}
if (!hasMultipleTracks) {
- off64_t offset = mIsAvc? mOwner->addLengthPrefixedSample_l(copy)
+ off64_t offset = (mIsAvc || mIsHEVC)? mOwner->addLengthPrefixedSample_l(copy)
: mOwner->addSample_l(copy);
uint32_t count = (mOwner->use32BitFileOffset()
@@ -2723,7 +2749,8 @@ status_t MPEG4Writer::Track::checkCodecSpecificData() const {
CHECK(mMeta->findCString(kKeyMIMEType, &mime));
if (!strcasecmp(MEDIA_MIMETYPE_AUDIO_AAC, mime) ||
!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
- !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
+ !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime) ||
+ mIsHEVC) {
if (!mCodecSpecificData ||
mCodecSpecificDataSize <= 0) {
ALOGE("Missing codec specific data");
@@ -2832,9 +2859,16 @@ void MPEG4Writer::Track::writeVideoFourCCBox() {
writeD263Box();
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
writeAvccBox();
+ } else if (mIsHEVC) {
+ AVUtils::get()->HEVCMuxerUtils().writeHvccBox(mOwner, mCodecSpecificData,
+ mCodecSpecificDataSize,
+ mOwner->useNalLengthFour());
+ }
+
+ if (!mIsHEVC) {
+ writePaspBox();
}
- writePaspBox();
mOwner->endBox(); // mp4v, s263 or avc1
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 5339c82..935fbf7 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -668,6 +668,8 @@ void convertMessageToMetaData(const sp<AMessage> &msg, sp<MetaData> &meta) {
// for transporting the CSD to muxers.
reassembleESDS(csd0, esds);
meta->setData(kKeyESDS, kKeyESDS, esds, sizeof(esds));
+ } else {
+ AVUtils::get()->HEVCMuxerUtils().reassembleHEVCCSD(mime, csd0, meta);
}
}