summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLeena Winterrowd <lenhardw@codeaurora.org>2014-09-10 19:22:54 -0700
committerSteve Kondik <steve@cyngn.com>2015-11-30 15:04:08 -0800
commitd69ffb9cf12a4664584e0b3eea30e23b95db4ad0 (patch)
treef6134cec387a1d95ade4ba7d33b74aafc51a4d22
parent46c4173bc9b415b443f2705675dd5785f0c4c46c (diff)
downloadframeworks_av-d69ffb9cf12a4664584e0b3eea30e23b95db4ad0.zip
frameworks_av-d69ffb9cf12a4664584e0b3eea30e23b95db4ad0.tar.gz
frameworks_av-d69ffb9cf12a4664584e0b3eea30e23b95db4ad0.tar.bz2
libstagefright: Handle MPEG4 DP playback
Since the HW decoder doesn't support MPEG4 DP clips, detect DP format clips in the parser and report a new MIME: video/mpeg4-esdp. This MIME is only registered to the SW decoder which supports DP clips. Merges the following change from kitkat: libstagefright: Fix DP Parsing issue with mpeg4 SP,ASP (Change-Id: I69c719011e1a0d2a0b0ae5a9b504b7cce443866b) CRs-Fixed: 722066 Change-Id: I7bc3a7a9f4a6d37e046ed9c8008cb27fb3bc665d
-rw-r--r--include/media/stagefright/Utils.h4
-rw-r--r--media/libstagefright/ACodec.cpp2
-rwxr-xr-xmedia/libstagefright/MPEG4Extractor.cpp3
-rw-r--r--media/libstagefright/OMXCodec.cpp8
-rw-r--r--media/libstagefright/Utils.cpp223
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp2
-rw-r--r--media/libstagefright/rtsp/APacketSource.cpp3
7 files changed, 243 insertions, 2 deletions
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
index 1e9de1a..847ea36 100644
--- a/include/media/stagefright/Utils.h
+++ b/include/media/stagefright/Utils.h
@@ -87,6 +87,10 @@ void readFromAMessage(
audio_format_t getPCMFormat(const sp<AMessage> &format);
+void updateVideoTrackInfoFromESDS_MPEG4Video(sp<MetaData> meta);
+bool checkDPFromVOLHeader(const uint8_t *ptr, size_t size);
+bool checkDPFromCodecSpecificData(const uint8_t *ptr, size_t size);
+
} // namespace android
#endif // UTILS_H_
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 6c4fd76..f7cc4cd 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1590,6 +1590,8 @@ status_t ACodec::setComponentRole(
"audio_decoder.ac3", "audio_encoder.ac3" },
{ MEDIA_MIMETYPE_AUDIO_EAC3,
"audio_decoder.eac3", "audio_encoder.eac3" },
+ { MEDIA_MIMETYPE_VIDEO_MPEG4_DP,
+ "video_decoder.mpeg4", NULL },
};
static const size_t kNumMimeToRole =
diff --git a/media/libstagefright/MPEG4Extractor.cpp b/media/libstagefright/MPEG4Extractor.cpp
index 738b134..d0dba73 100755
--- a/media/libstagefright/MPEG4Extractor.cpp
+++ b/media/libstagefright/MPEG4Extractor.cpp
@@ -1718,6 +1718,9 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
}
}
}
+
+ updateVideoTrackInfoFromESDS_MPEG4Video(mLastTrack->meta);
+
break;
}
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 3ec02d4..d387236 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -905,7 +905,8 @@ void OMXCodec::setVideoInputFormat(
compressionFormat = OMX_VIDEO_CodingAVC;
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
compressionFormat = OMX_VIDEO_CodingHEVC;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
+ !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4_DP, mime)) {
compressionFormat = OMX_VIDEO_CodingMPEG4;
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) {
compressionFormat = OMX_VIDEO_CodingH263;
@@ -1297,7 +1298,8 @@ status_t OMXCodec::setVideoOutputFormat(
OMX_VIDEO_CODINGTYPE compressionFormat = OMX_VIDEO_CodingUnused;
if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) {
compressionFormat = OMX_VIDEO_CodingAVC;
- } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) {
+ } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime) ||
+ !strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4_DP, mime)) {
compressionFormat = OMX_VIDEO_CodingMPEG4;
} else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) {
compressionFormat = OMX_VIDEO_CodingHEVC;
@@ -1499,6 +1501,8 @@ void OMXCodec::setComponentRole(
"video_decoder.hevc", "video_encoder.hevc" },
{ MEDIA_MIMETYPE_VIDEO_MPEG4,
"video_decoder.mpeg4", "video_encoder.mpeg4" },
+ { MEDIA_MIMETYPE_VIDEO_MPEG4_DP,
+ "video_decoder.mpeg4", NULL },
{ MEDIA_MIMETYPE_VIDEO_H263,
"video_decoder.h263", "video_encoder.h263" },
{ MEDIA_MIMETYPE_VIDEO_VP8,
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 6d62e03..2aaff6c 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -37,6 +37,7 @@
#include <stagefright/AVExtensions.h>
#include <media/stagefright/FFMPEGSoftCodec.h>
+#include <media/stagefright/foundation/ABitReader.h>
namespace android {
@@ -1057,5 +1058,227 @@ audio_format_t getPCMFormat(const sp<AMessage> &format) {
return AUDIO_FORMAT_PCM_16_BIT;
}
+void updateVideoTrackInfoFromESDS_MPEG4Video(sp<MetaData> meta) {
+ const char* mime = NULL;
+ if (meta != NULL && meta->findCString(kKeyMIMEType, &mime) &&
+ mime && !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4)) {
+ uint32_t type;
+ const void *data;
+ size_t size;
+ if (!meta->findData(kKeyESDS, &type, &data, &size) || !data) {
+ ALOGW("ESDS atom is invalid");
+ return;
+ }
+
+ if (checkDPFromCodecSpecificData((const uint8_t*) data, size)) {
+ meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG4_DP);
+ }
+ }
+}
+
+bool checkDPFromCodecSpecificData(const uint8_t *data, size_t size) {
+ bool retVal = false;
+ size_t offset = 0, startCodeOffset = 0;
+ bool isStartCode = false;
+ const int kVolStartCode = 0x20;
+ const char kStartCode[] = "\x00\x00\x01";
+ // must contain at least 4 bytes for video_object_layer_start_code
+ const size_t kMinCsdSize = 4;
+
+ if (!data || (size < kMinCsdSize)) {
+ ALOGV("Invalid CSD (expected at least %zu bytes)", kMinCsdSize);
+ return retVal;
+ }
+
+ while (offset < size - 3) {
+ if ((data[offset + 3] & 0xf0) == kVolStartCode) {
+ if (!memcmp(&data[offset], kStartCode, 3)) {
+ startCodeOffset = offset;
+ isStartCode = true;
+ break;
+ }
+ }
+
+ offset++;
+ }
+
+ if (isStartCode) {
+ retVal = checkDPFromVOLHeader((const uint8_t*) &data[startCodeOffset],
+ (size - startCodeOffset));
+ }
+
+ return retVal;
+}
+
+bool checkDPFromVOLHeader(const uint8_t *data, size_t size) {
+ bool retVal = false;
+ // must contain at least 4 bytes for video_object_layer_start_code + 9 bits of data
+ const size_t kMinHeaderSize = 6;
+
+ if (!data || (size < kMinHeaderSize)) {
+ ALOGV("Invalid VOL header (expected at least %zu bytes)", kMinHeaderSize);
+ return false;
+ }
+
+ ALOGV("Checking for MPEG4 DP bit");
+ ABitReader br(&data[4], (size - 4));
+ br.skipBits(1); // random_accessible_vol
+
+ unsigned videoObjectTypeIndication = br.getBits(8);
+ if (videoObjectTypeIndication == 0x12u) {
+ ALOGW("checkDPFromVOLHeader: videoObjectTypeIndication:%u",
+ videoObjectTypeIndication);
+ return false;
+ }
+
+ unsigned videoObjectLayerVerid = 1;
+ if (br.getBits(1)) {
+ videoObjectLayerVerid = br.getBits(4);
+ br.skipBits(3); // video_object_layer_priority
+ ALOGV("checkDPFromVOLHeader: videoObjectLayerVerid:%u",
+ videoObjectLayerVerid);
+ }
+
+ if (br.getBits(4) == 0x0f) { // aspect_ratio_info
+ ALOGV("checkDPFromVOLHeader: 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
+ br.skipBits(15); // first_half_bit_rate
+ br.skipBits(1); // marker_bit
+ br.skipBits(15); // latter_half_bit_rate
+ br.skipBits(1); // marker_bit
+ br.skipBits(15); // first_half_vbv_buffer_size
+ br.skipBits(1); // marker_bit
+ br.skipBits(3); // latter_half_vbv_buffer_size
+ br.skipBits(11); // first_half_vbv_occupancy
+ br.skipBits(1); // marker_bit
+ br.skipBits(15); // latter_half_vbv_occupancy
+ br.skipBits(1); // marker_bit
+ }
+ }
+
+ unsigned videoObjectLayerShape = br.getBits(2);
+ if (videoObjectLayerShape != 0x00u /* rectangular */) {
+ ALOGV("checkDPFromVOLHeader: videoObjectLayerShape:%x",
+ videoObjectLayerShape);
+ return false;
+ }
+
+ br.skipBits(1); // marker_bit
+ unsigned vopTimeIncrementResolution = br.getBits(16);
+ br.skipBits(1); // marker_bit
+ if (br.getBits(1)) { // fixed_vop_rate
+ // range [0..vopTimeIncrementResolution)
+
+ // vopTimeIncrementResolution
+ // 2 => 0..1, 1 bit
+ // 3 => 0..2, 2 bits
+ // 4 => 0..3, 2 bits
+ // 5 => 0..4, 3 bits
+ // ...
+
+ if (vopTimeIncrementResolution <= 0u) {
+ return BAD_VALUE;
+ }
+
+ --vopTimeIncrementResolution;
+ unsigned numBits = 0;
+ while (vopTimeIncrementResolution > 0) {
+ ++numBits;
+ vopTimeIncrementResolution >>= 1;
+ }
+
+ br.skipBits(numBits); // fixed_vop_time_increment
+ }
+
+ br.skipBits(1); // marker_bit
+ br.skipBits(13); // video_object_layer_width
+ br.skipBits(1); // marker_bit
+ br.skipBits(13); // video_object_layer_height
+ br.skipBits(1); // marker_bit
+ br.skipBits(1); // interlaced
+ br.skipBits(1); // obmc_disable
+ unsigned spriteEnable = 0;
+ if (videoObjectLayerVerid == 1) {
+ spriteEnable = br.getBits(1);
+ } else {
+ spriteEnable = br.getBits(2);
+ }
+
+ if (spriteEnable == 0x1) { // static
+ int spriteWidth = br.getBits(13);
+ ALOGV("checkDPFromVOLHeader: spriteWidth:%d", spriteWidth);
+ br.skipBits(1) ; // marker_bit
+ br.skipBits(13); // sprite_height
+ br.skipBits(1); // marker_bit
+ br.skipBits(13); // sprite_left_coordinate
+ br.skipBits(1); // marker_bit
+ br.skipBits(13); // sprite_top_coordinate
+ br.skipBits(1); // marker_bit
+ br.skipBits(6); // no_of_sprite_warping_points
+ br.skipBits(2); // sprite_warping_accuracy
+ br.skipBits(1); // sprite_brightness_change
+ br.skipBits(1); // low_latency_sprite_enable
+ } else if (spriteEnable == 0x2) { // GMC
+ br.skipBits(6); // no_of_sprite_warping_points
+ br.skipBits(2); // sprite_warping_accuracy
+ br.skipBits(1); // sprite_brightness_change
+ }
+
+ if (videoObjectLayerVerid != 1
+ && videoObjectLayerShape != 0x0u) {
+ br.skipBits(1);
+ }
+
+ if (br.getBits(1)) { // not_8_bit
+ br.skipBits(4); // quant_precision
+ br.skipBits(4); // bits_per_pixel
+ }
+
+ if (videoObjectLayerShape == 0x3) {
+ br.skipBits(1);
+ br.skipBits(1);
+ br.skipBits(1);
+ }
+
+ if (br.getBits(1)) { // quant_type
+ if (br.getBits(1)) { // load_intra_quant_mat
+ unsigned IntraQuantMat = 1;
+ for (int i = 0; i < 64 && IntraQuantMat; i++) {
+ IntraQuantMat = br.getBits(8);
+ }
+ }
+
+ if (br.getBits(1)) { // load_non_intra_quant_matrix
+ unsigned NonIntraQuantMat = 1;
+ for (int i = 0; i < 64 && NonIntraQuantMat; i++) {
+ NonIntraQuantMat = br.getBits(8);
+ }
+ }
+ } /* quantType */
+
+ if (videoObjectLayerVerid != 1) {
+ unsigned quarterSample = br.getBits(1);
+ ALOGV("checkDPFromVOLHeader: quarterSample:%u",
+ quarterSample);
+ }
+
+ br.skipBits(1); // complexity_estimation_disable
+ br.skipBits(1); // resync_marker_disable
+ unsigned dataPartitioned = br.getBits(1);
+ if (dataPartitioned) {
+ retVal = true;
+ }
+
+ ALOGD("checkDPFromVOLHeader: DP:%u", dataPartitioned);
+ return retVal;
+}
+
} // namespace android
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index 06057d0..f8fa015 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -903,6 +903,8 @@ static void addESDSFromCodecPrivate(
meta->setData(kKeyESDS, 0, esds, esdsSize);
+ updateVideoTrackInfoFromESDS_MPEG4Video(meta);
+
delete[] esds;
esds = NULL;
}
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index cfafaa7..e81325d 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -37,6 +37,7 @@
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
#include <utils/Vector.h>
namespace android {
@@ -535,6 +536,8 @@ APacketSource::APacketSource(
return;
}
+ updateVideoTrackInfoFromESDS_MPEG4Video(mFormat);
+
mFormat->setInt32(kKeyWidth, width);
mFormat->setInt32(kKeyHeight, height);
} else if (!strncasecmp(desc.c_str(), "mpeg4-generic/", 14)) {