Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8a05b94e authored by Hangyu Kuang's avatar Hangyu Kuang Committed by Android (Google) Code Review
Browse files

Merge changes from topic "metadata-trackfix"

* changes:
  MPEG4Extractor: Read out the Metadata track correctly.
  MPEG4Writer: Fix the bug in MPEG4 metadata track.
parents 4f20844f 0b490550
Loading
Loading
Loading
Loading
+33 −2
Original line number Diff line number Diff line
@@ -1553,9 +1553,40 @@ status_t MPEG4Extractor::parseChunk(off64_t *offset, int depth) {
                return ERROR_IO;
            }

            String8 mimeFormat((const char *)(buffer.get()), chunk_data_size);
            AMediaFormat_setString(mLastTrack->meta, AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
            // Prior to API 29, the metadata track was not compliant with ISO/IEC
            // 14496-12-2015. This led to some ISO-compliant parsers failing to read the
            // metatrack. As of API 29 and onwards, a change was made to metadata track to
            // make it compliant with the standard. The workaround is to write the
            // null-terminated mime_format string twice. This allows compliant parsers to
            // read the missing reserved, data_reference_index, and content_encoding fields
            // from the first mime_type string. The actual mime_format field would then be
            // read correctly from the second string. The non-compliant Android frameworks
            // from API 28 and earlier would still be able to read the mime_format correctly
            // as it would only read the first null-terminated mime_format string. To enable
            // reading metadata tracks generated from both the non-compliant and compliant
            // formats, a check needs to be done to see which format is used.
            int null_pos = 0;
            const unsigned char *str = buffer.get();
            while (null_pos < chunk_data_size) {
              if (*(str + null_pos) == '\0') {
                break;
              }
              ++null_pos;
            }

            if (null_pos == chunk_data_size - 1) {
              // This is not a standard ompliant metadata track.
              String8 mimeFormat((const char *)(buffer.get()), chunk_data_size);
              AMediaFormat_setString(mLastTrack->meta,
                  AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
            } else {
              // This is a standard compliant metadata track.
              String8 contentEncoding((const char *)(buffer.get() + 8));
              String8 mimeFormat((const char *)(buffer.get() + 8 + contentEncoding.size() + 1),
                  chunk_data_size - 8 - contentEncoding.size() - 1);
              AMediaFormat_setString(mLastTrack->meta,
                  AMEDIAFORMAT_KEY_MIME, mimeFormat.string());
            }
            break;
        }

+23 −0
Original line number Diff line number Diff line
@@ -3674,6 +3674,29 @@ void MPEG4Writer::Track::writeMetadataFourCCBox() {
        TRESPASS();
    }
    mOwner->beginBox(fourcc);    // TextMetaDataSampleEntry

    //  HACK to make the metadata track compliant with the ISO standard.
    //
    //  Metadata track is added from API 26 and the original implementation does not
    //  fully followed the TextMetaDataSampleEntry specified in ISO/IEC 14496-12-2015
    //  in that only the mime_format is written out. content_encoding and
    //  data_reference_index have not been written out. This leads to the failure
    //  when some MP4 parser tries to parse the metadata track according to the
    //  standard. The hack here will make the metadata track compliant with the
    //  standard while still maintaining backwards compatibility. This would enable
    //  Android versions before API 29 to be able to read out the standard compliant
    //  Metadata track generated with Android API 29 and upward. The trick is based
    //  on the fact that the Metadata track must start with prefix “application/” and
    //  those missing fields are not used in Android's Metadata track. By writting
    //  out the mime_format twice, the first mime_format will be used to fill out the
    //  missing reserved, data_reference_index and content encoding fields. On the
    //  parser side, the extracter before API 29  will read out the first mime_format
    //  correctly and drop the second mime_format. The extractor from API 29 will
    //  check if the reserved, data_reference_index and content encoding are filled
    //  with “application” to detect if this is a standard compliant metadata track
    //  and read out the data accordingly.
    mOwner->writeCString(mime);

    mOwner->writeCString(mime);  // metadata mime_format
    mOwner->endBox(); // mett
}