Skip to content

Commit 0c8adfc

Browse files
committed
Fix #2049
1 parent 8fb7d1d commit 0c8adfc

File tree

2 files changed

+59
-5
lines changed

2 files changed

+59
-5
lines changed

av/container/output.py

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,15 +278,23 @@ def add_data_stream(self, codec_name=None, options: dict | None = None):
278278
:rtype: The new :class:`~av.data.stream.DataStream`.
279279
"""
280280
codec: cython.pointer[cython.const[lib.AVCodec]] = cython.NULL
281+
codec_descriptor: cython.pointer[lib.AVCodecDescriptor] = cython.NULL
281282

282283
if codec_name is not None:
283284
codec = lib.avcodec_find_encoder_by_name(codec_name.encode())
284285
if codec == cython.NULL:
285-
raise ValueError(f"Unknown data codec: {codec_name}")
286+
codec = lib.avcodec_find_decoder_by_name(codec_name.encode())
287+
if codec == cython.NULL:
288+
codec_descriptor = lib.avcodec_descriptor_get_by_name(
289+
codec_name.encode()
290+
)
291+
if codec_descriptor == cython.NULL:
292+
raise ValueError(f"Unknown data codec: {codec_name}")
286293

287-
# Assert that this format supports the requested codec
294+
# Verify format supports this codec
295+
codec_id = codec.id if codec != cython.NULL else codec_descriptor.id
288296
if not lib.avformat_query_codec(
289-
self.ptr.oformat, codec.id, lib.FF_COMPLIANCE_NORMAL
297+
self.ptr.oformat, codec_id, lib.FF_COMPLIANCE_NORMAL
290298
):
291299
raise ValueError(
292300
f"{self.format.name!r} format does not support {codec_name!r} codec"
@@ -297,7 +305,7 @@ def add_data_stream(self, codec_name=None, options: dict | None = None):
297305
if stream == cython.NULL:
298306
raise MemoryError("Could not allocate stream")
299307

300-
# Set up codec context if we have a codec
308+
# Set up codec context and parameters
301309
ctx: cython.pointer[lib.AVCodecContext] = cython.NULL
302310
if codec != cython.NULL:
303311
ctx = lib.avcodec_alloc_context3(codec)
@@ -311,8 +319,10 @@ def add_data_stream(self, codec_name=None, options: dict | None = None):
311319
# Initialize stream codec parameters
312320
err_check(lib.avcodec_parameters_from_context(stream.codecpar, ctx))
313321
else:
314-
# For raw data streams, just set the codec type
322+
# No codec available - set basic parameters for data stream
315323
stream.codecpar.codec_type = lib.AVMEDIA_TYPE_DATA
324+
if codec_descriptor != cython.NULL:
325+
stream.codecpar.codec_id = codec_descriptor.id
316326

317327
# Construct the user-land stream
318328
py_codec_context: CodecContext | None = None

tests/test_streams.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ def cleanup(self):
1717
"data.ts",
1818
"data_source.ts",
1919
"data_copy.ts",
20+
"data_with_codec.ts",
21+
"data_invalid.ts",
2022
"out.mkv",
2123
"video_with_attachment.mkv",
2224
"remuxed_attachment.mkv",
@@ -201,6 +203,48 @@ def test_data_stream_from_template(self) -> None:
201203

202204
assert remuxed_payloads == copied_payloads
203205

206+
def test_data_stream_with_codec(self) -> None:
207+
"""Test adding a data stream with a specific codec name."""
208+
# Test that invalid codec names raise appropriate errors
209+
with pytest.raises(ValueError, match="Unknown data codec"):
210+
container = av.open("data_invalid.ts", "w")
211+
try:
212+
container.add_data_stream("not_a_real_codec_name_12345")
213+
finally:
214+
container.close()
215+
216+
# Test that add_data_stream with codec parameter works correctly
217+
# We use "bin_data" which is a data codec that's always available
218+
output_path = "data_with_codec.ts"
219+
with av.open(output_path, "w") as container:
220+
# Try to create a data stream with a codec
221+
# bin_data is a simple passthrough codec for binary data
222+
data_stream = container.add_data_stream("bin_data")
223+
klv_stream = container.add_data_stream("klv")
224+
225+
assert data_stream.type == "data"
226+
assert klv_stream.type == "data"
227+
# Note: codec_context may be None for descriptor-only data codecs
228+
229+
test_data = [b"test1", b"test2", b"test3"]
230+
for i, data in enumerate(test_data):
231+
packet = av.Packet(data)
232+
packet.pts = i
233+
packet.stream = data_stream
234+
container.mux(packet)
235+
236+
with av.open(output_path) as newcontainer:
237+
data_stream = newcontainer.streams.data[0]
238+
klv_stream = newcontainer.streams.data[1]
239+
assert "klv" in str(klv_stream)
240+
assert "bin_data" in str(data_stream)
241+
assert data_stream.type == "data"
242+
assert klv_stream.type == "data"
243+
try:
244+
os.remove(output_path)
245+
except Exception:
246+
pass
247+
204248
def test_attachment_stream(self) -> None:
205249
input_path = av.datasets.curated(
206250
"pexels/time-lapse-video-of-night-sky-857195.mp4"

0 commit comments

Comments
 (0)