Closed Bug 778050 Opened 12 years ago Closed 12 years ago

Support Opus tag metadata

Categories

(Core :: Audio/Video, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla18

People

(Reporter: rillian, Assigned: rillian)

References

Details

Attachments

(1 file, 3 obsolete files)

Opus files have key=value metadata in the second header packet, in a similar format to vorbis and theora. Currently we ignore this.

Instead we should parse this header and make the data available through media.mozGetMetadata(). libopus doesn't container a parser, so we'd need to write one and use it fill in an nsHTMLMediaElement::MetadataTags hashtable, to be returned by nsOggReader::ReadMetadata() as it is for vorbis.
Can test with https://people.xiph.org/~giles/2012/metadata-opus.html

The parse code is a bit hybrid. 

I copy the raw comment strings into an array of nsCString in ::DecodeHeader, and only do full validation when generating the hash table. This makes us no more strict than before.

I convert the comments back to C strings and parse them the same was I did for Vorbis, which seemed shorter, but it's a bit of a hybrid between C strings and nsCStrings. I considered parsing them into an array of char* instead, if you like that better. Parsing them into a vorbis_comment struct would let us share the validation and hash table generation, but introduces a dependency between the two codecs.
Assignee: nobody → giles
Attachment #660594 - Flags: review?(tterribe)
Attached patch Support Opus tag metadata (obsolete) — Splinter Review
an array member variable. Add a method to generate
the nsHTMLMediaElement::MetadataTags hash table from
those entries, performing the same validatation we
do for Vorbis.

IsValidVorbisTagName is promoted to a static method
on nsOggReader so we can use it externally.

This feature is tested by adding the existing opus
test file to gMetadataTests.
Comment on attachment 660608 [details] [diff] [review]
Support Opus tag metadata

Update patch to include a test case.
Attachment #660608 - Attachment description: Support Opus tag metadata - parsed comments from the OpusTags header in → Support Opus tag metadata
Attachment #660608 - Flags: review?(tterribe)
Attachment #660594 - Attachment is obsolete: true
Attachment #660594 - Flags: review?(tterribe)
Attached patch Support Opus tag metadata (obsolete) — Splinter Review
Update to fix a debug message typo. Sorry for the noise.

pushed to try as https://tbpl.mozilla.org/?tree=Try&rev=803d96343a8b
Attachment #660608 - Attachment is obsolete: true
Attachment #660608 - Flags: review?(tterribe)
Attachment #660613 - Flags: review?(tterribe)
Try push is green. Orange is three timeouts in unrelated test sections.
Comment on attachment 660613 [details] [diff] [review]
Support Opus tag metadata

Review of attachment 660613 [details] [diff] [review]:
-----------------------------------------------------------------

I don't think there's anything functionally wrong with this patch, so I'll r+ it, but I think we could organize things a little better. Feel free to rework and resubmit if you agree.

::: content/media/ogg/nsOggCodecState.cpp
@@ +930,1 @@
>        uint32_t bytes = aPacket->bytes - 8;

There's a comment at line 922 here that says things that are untrue after applying this patch. Please update it.

@@ +934,5 @@
>        buf += 4;
>        bytes -= 4;
>        if (len > bytes)
>          return false;
> +      mVendorString = nsCString(reinterpret_cast<const char*>(buf), len);

I'd personally prefer static_cast<> here (and where used below), though I can't imagine it ever making a practical difference.

@@ +983,5 @@
>    }
>    return true;
>  }
>  
> +/* Construct and return a tags hashmap from our internal array */

Apart from the codec duplication (see below), the thing that bothers me here is that this lives in a completely different file from TagsFromVorbisComment(). If they were in the same place, then if someone updates one, there's at least a fighting chance they'll notice and update the other. Perhaps put this function in nsOggReader and have it take a const nsTArray<nsCstring> & returned by nsOpusState::GetTags()? That would also avoid the need to include nsOggReader.h here.

Alternatively, you could make this a virtual method of nsOggCodecState, with a default implementation that just returns NULL until we implement tag parsing for all codecs, and have both implementations in nsOggCodecState. That approach feels somewhat cleaner to me.

@@ +992,5 @@
> +  tags = new nsHTMLMediaElement::MetadataTags;
> +  tags->Init();
> +  for (uint32_t i = 0; i < mTags.Length(); i++) {
> +    const char* comment = mTags[i].Data();
> +    uint32_t length = mTags[i].Length();

Everything from here down to the Put() call is identical to the code in TagsFromVorbisComment(), except for the debug logging. I'd recommend putting this in a
  static void AddVorbisComment(nsHtmlMediaElement *aTags, const char *aComment, uint32_t aLength)
function that does all three checks (and the Put(), too).

::: content/media/ogg/nsOggReader.cpp
@@ +159,5 @@
>      }
>    }
>  }
>  
> +bool nsOggReader::IsValidVorbisTagName(nsCString& name)

I know this isn't new code, but while you're here, isn't local style to call this aName?
Attachment #660613 - Flags: review?(tterribe) → review+
Comment on attachment 660613 [details] [diff] [review]
Support Opus tag metadata

Review of attachment 660613 [details] [diff] [review]:
-----------------------------------------------------------------

Ok, thanks for the comments. I'll see if I can move the calls to the same file in a sensible way.

::: content/media/ogg/nsOggCodecState.cpp
@@ +930,1 @@
>        uint32_t bytes = aPacket->bytes - 8;

Thanks.

@@ +934,5 @@
>        buf += 4;
>        bytes -= 4;
>        if (len > bytes)
>          return false;
> +      mVendorString = nsCString(reinterpret_cast<const char*>(buf), len);

static_cast doesn't work here. It will only perform a cast that could be done by an implicit conversion, and C++ won't implicitly convert unsigned to signed.

C-style casts work of course, but cpearce has asked for C++ casts as part of local style in the past.

::: content/media/ogg/nsOggReader.cpp
@@ +159,5 @@
>      }
>    }
>  }
>  
> +bool nsOggReader::IsValidVorbisTagName(nsCString& name)

Good catch.
Attached patch updated fixSplinter Review
Updating in response to comments. I moved things to nsOggCodecState instead of into nsOggReader. That seemed to make more sense to me.
Attachment #660613 - Attachment is obsolete: true
Attachment #661439 - Flags: review?(tterribe)
Comment on attachment 661439 [details] [diff] [review]
updated fix

Review of attachment 661439 [details] [diff] [review]:
-----------------------------------------------------------------

This looks much cleaner, thanks!

::: content/media/ogg/nsOggCodecState.cpp
@@ +122,5 @@
> +  // excluding 0x3D '=' which is the separator.
> +  uint32_t length = aName.Length();
> +  const char* data = aName.Data();
> +  for (uint32_t i = 0; i < length; i++) {
> +    if (data[i] < 0x20 || data[i] > 0x7D || data[i] == '=') {

You know, it occurs to me that with the memchr() call below, checking for '=' here is redundant.
Attachment #661439 - Flags: review?(tterribe) → review+
(In reply to Timothy B. Terriberry (:derf) from comment #10)

> You know, it occurs to me that with the memchr() call below, checking for
> '=' here is redundant.

That's correct. I thought it was better to validate that in case the method is called from a different context later.

Ready to land. Try push is green, but for some reason doesn't report on mochitest-1 on Mac. I'll reverify that locally on 10.7.
Keywords: checkin-needed
Local run of the media mochitests on MacOS 10.7 was green.
(In reply to Ralph Giles (:rillian) from comment #9)
> Pushed to try as https://tbpl.mozilla.org/?tree=Try&rev=ef0751b8a559

Green on Try.

https://hg.mozilla.org/integration/mozilla-inbound/rev/562ab305f2f3
Flags: in-testsuite+
Keywords: checkin-needed
https://hg.mozilla.org/mozilla-central/rev/562ab305f2f3
Status: NEW → RESOLVED
Closed: 12 years ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla18
Does this support streaming ogg as well?

http://dir.xiph.org/by_format/Ogg_Vorbis

Or does it only get the meta data at first load?
Ignore my question, answer is yes. I tested it.
https://people.xiph.org/~giles/2013/metadata.html has some current examples, so you can see the metadata change.
You need to log in before you can comment on or make changes to this bug.