gxf: add timecode information to metadata

Signed-off-by: Reimar Döffinger <Reimar.Doeffinger@gmx.de>
This commit is contained in:
Matthieu Bouron 2011-10-31 19:54:31 +01:00 committed by Reimar Döffinger
parent 078811d9e4
commit 2264afa1c2
1 changed files with 45 additions and 3 deletions

View File

@ -29,8 +29,30 @@ struct gxf_stream_info {
int64_t last_field;
AVRational frames_per_second;
int32_t fields_per_frame;
int64_t track_aux_data;
};
/**
* @brief parse gxf timecode and add it to metadata
*/
static int add_timecode_metadata(AVDictionary **pm, const char *key, uint32_t timecode, int fields_per_frame)
{
char tmp[128];
int field = timecode & 0xff;
int frame = fields_per_frame ? field / fields_per_frame : field;
int second = (timecode >> 8) & 0xff;
int minute = (timecode >> 16) & 0xff;
int hour = (timecode >> 24) & 0x1f;
int drop = (timecode >> 29) & 1;
// bit 30: color_frame, unused
// ignore invalid time code
if (timecode >> 31)
return 0;
snprintf(tmp, sizeof(tmp), "%02d:%02d:%02d%c%02d",
hour, minute, second, drop ? ';' : ':', frame);
return av_dict_set(pm, key, tmp, 0);
}
/**
* @brief parses a packet header, extracting type and length
* @param pb AVIOContext to read header from
@ -210,6 +232,7 @@ static AVRational fps_umf2avr(uint32_t flags) {
static void gxf_track_tags(AVIOContext *pb, int *len, struct gxf_stream_info *si) {
si->frames_per_second = (AVRational){0, 0};
si->fields_per_frame = 0;
si->track_aux_data = 0x80000000;
while (*len >= 2) {
GXFTrackTag tag = avio_r8(pb);
int tlen = avio_r8(pb);
@ -223,7 +246,9 @@ static void gxf_track_tags(AVIOContext *pb, int *len, struct gxf_stream_info *si
si->frames_per_second = fps_tag2avr(value);
else if (tag == TRACK_FPF && (value == 1 || value == 2))
si->fields_per_frame = value;
} else
} else if (tlen == 8 && tag == TRACK_AUX)
si->track_aux_data = avio_rl64(pb);
else
avio_skip(pb, tlen);
}
}
@ -301,8 +326,6 @@ static int gxf_header(AVFormatContext *s, AVFormatParameters *ap) {
track_id = avio_r8(pb);
track_len = avio_rb16(pb);
len -= track_len;
gxf_track_tags(pb, &track_len, si);
avio_skip(pb, track_len);
if (!(track_type & 0x80)) {
av_log(s, AV_LOG_ERROR, "invalid track type %x\n", track_type);
continue;
@ -313,6 +336,16 @@ static int gxf_header(AVFormatContext *s, AVFormatParameters *ap) {
continue;
}
track_id &= 0x3f;
gxf_track_tags(pb, &track_len, si);
// check for timecode tracks
if (track_type == 7 || track_type == 8 || track_type == 24) {
add_timecode_metadata(&s->metadata, "gxf_timecode",
si->track_aux_data & 0xffffffff,
si->fields_per_frame);
}
avio_skip(pb, track_len);
idx = get_sindex(s, track_id, track_type);
if (idx < 0) continue;
st = s->streams[idx];
@ -353,6 +386,15 @@ static int gxf_header(AVFormatContext *s, AVFormatParameters *ap) {
main_timebase.num = fps.den;
main_timebase.den = fps.num * 2;
}
if (len >= 0x18) {
len -= 0x18;
avio_skip(pb, 0x10);
add_timecode_metadata(&s->metadata, "gxf_timecode_at_mark_in",
avio_rl32(pb), si->fields_per_frame);
add_timecode_metadata(&s->metadata, "gxf_timecode_at_mark_out",
avio_rl32(pb), si->fields_per_frame);
}
} else
av_log(s, AV_LOG_INFO, "UMF packet too short\n");
} else