Skip to content

Commit bb34ac0

Browse files
darbyjohnstonlgritz
authored andcommitted
feat(ffmpeg): FFmpeg additional metadata (#4396)
This change adds additional FFmpeg metadata from the video and data streams. These streams can hold the start timecode which is very useful in OpenTimelineIO applications. I also added `av_guess_frame_rate()` which might be more robust than just checking `stream->avg_frame_rate`, but I can also create a separate PR if it is better to break it up. It doesn't look like there are any FFmpeg tests in `testsuite`? I tested with the DPEL ALab trailer and some Netflix Open Content movies, and was able to see the timecode metadata in the OIIO image attributes. --------- Signed-off-by: Darby Johnston <[email protected]>
1 parent 2c00908 commit bb34ac0

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

src/doc/builtinplugins.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,9 @@ Some special attributes are used for movie files:
12521252
* - ``FramesPerSecond``
12531253
- int[2] (rational)
12541254
- Frames per second
1255+
* - ``ffmpeg:TimeCode``
1256+
- string
1257+
- Start time timecode
12551258

12561259

12571260

src/ffmpeg.imageio/ffmpeginput.cpp

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ class FFmpegInput final : public ImageInput {
130130
std::vector<uint8_t> m_rgb_buffer;
131131
std::vector<int> m_video_indexes;
132132
int m_video_stream;
133+
int m_data_stream;
133134
int64_t m_frames;
134135
int m_last_search_pos;
135136
int m_last_decoded_pos;
@@ -152,6 +153,7 @@ class FFmpegInput final : public ImageInput {
152153
m_rgb_buffer.clear();
153154
m_video_indexes.clear();
154155
m_video_stream = -1;
156+
m_data_stream = -1;
155157
m_frames = 0;
156158
m_last_search_pos = 0;
157159
m_last_decoded_pos = 0;
@@ -263,6 +265,14 @@ FFmpegInput::open(const std::string& name, ImageSpec& spec)
263265
errorfmt("\"{}\" could not find a valid videostream", file_name);
264266
return false;
265267
}
268+
for (unsigned int i = 0; i < m_format_context->nb_streams; i++) {
269+
if (stream_codec(i)->codec_type == AVMEDIA_TYPE_DATA) {
270+
if (m_data_stream < 0) {
271+
m_data_stream = i;
272+
break;
273+
}
274+
}
275+
}
266276

267277
// codec context for videostream
268278
#if USE_FFMPEG_3_1
@@ -309,9 +319,7 @@ FFmpegInput::open(const std::string& name, ImageSpec& spec)
309319
& AV_CODEC_CAP_DELAY);
310320

311321
AVStream* stream = m_format_context->streams[m_video_stream];
312-
if (stream->avg_frame_rate.num != 0 && stream->avg_frame_rate.den != 0) {
313-
m_frame_rate = stream->avg_frame_rate;
314-
}
322+
m_frame_rate = av_guess_frame_rate(m_format_context, stream, NULL);
315323

316324
m_frames = stream->nb_frames;
317325
m_start_time = stream->start_time;
@@ -514,6 +522,26 @@ FFmpegInput::open(const std::string& name, ImageSpec& spec)
514522
AV_DICT_IGNORE_SUFFIX))) {
515523
m_spec.attribute(tag->key, tag->value);
516524
}
525+
tag = NULL;
526+
if (m_data_stream >= 0) {
527+
while ((
528+
tag = av_dict_get(m_format_context->streams[m_data_stream]->metadata,
529+
"", tag, AV_DICT_IGNORE_SUFFIX))) {
530+
if (strcmp(tag->key, "timecode") == 0) {
531+
m_spec.attribute("ffmpeg:TimeCode", tag->value);
532+
break;
533+
}
534+
}
535+
}
536+
tag = NULL;
537+
while (
538+
(tag = av_dict_get(m_format_context->streams[m_video_stream]->metadata,
539+
"", tag, AV_DICT_IGNORE_SUFFIX))) {
540+
if (strcmp(tag->key, "timecode") == 0) {
541+
m_spec.attribute("ffmpeg:TimeCode", tag->value);
542+
break;
543+
}
544+
}
517545
int rat[2] = { m_frame_rate.num, m_frame_rate.den };
518546
m_spec.attribute("FramesPerSecond", TypeRational, &rat);
519547
m_spec.attribute("oiio:Movie", true);

0 commit comments

Comments
 (0)