Skip to content

Basic custom Ogg Opus comment tag write support #111

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions pyogg/ogg_opus_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@
import random
import struct
from typing import (
List,
Optional,
Union,
BinaryIO
)

from . import ogg
from . import opus
from . import __version__
from .opus_buffered_encoder import OpusBufferedEncoder
#from .opus_encoder import OpusEncoder
from .pyogg_error import PyOggError
Expand Down Expand Up @@ -55,6 +57,9 @@ def __init__(self,
# Create a new stream state with a random serial number
self._stream_state = self._create_stream_state()

# Do not add any user comments to the generated stream
self._user_comments: List[str] = []

# Create a packet (reused for each pass)
self._ogg_packet = ogg.ogg_packet()
self._packet_valid = False
Expand Down Expand Up @@ -122,6 +127,22 @@ def write(self, pcm: memoryview) -> None:
self._write_to_oggopus(pcm)


def add_user_comment(self, comment: str) -> None:
"""Appends an user comment string to the generated Ogg Opus stream.

Because such user comments are stored in Ogg Opus stream headers, calling
this method after they have been written (i.e., a call to the `write()`
method has been made) will have no effect. No user comments are written
by default.

Comment strings are meant to be short, for the purposes of stream
identification only, in the `KEY=VALUE` format. The headers format provides
some leeway to allow longer and differently formatted comments, however.
For more information and a list of conventional comment string key values,
please check out <https://www.xiph.org/vorbis/doc/v-comment.html>."""
self._user_comments.append(comment)


def _write_to_oggopus(self, pcm: memoryview, flush: bool = False) -> None:
assert self._encoder is not None

Expand Down Expand Up @@ -318,15 +339,22 @@ def _make_comment_header(self):

"""
signature = b"OpusTags"
vendor_string = b"ENCODER=PyOgg"
vendor_string = f"PyOgg {__version__}".encode("utf-8")
vendor_string_length = struct.pack("<I",len(vendor_string))
user_comments_length = struct.pack("<I",0)
user_comments_length = struct.pack("<I",len(self._user_comments))

user_comments = bytearray()
for user_comment in self._user_comments:
comment_string = user_comment.encode("utf-8")
user_comments += struct.pack("<I",len(comment_string))
user_comments += comment_string

return (
signature
+ vendor_string_length
+ vendor_string
+ user_comments_length
+ user_comments
)

def _write_comment_header_packet(self):
Expand Down