@@ -1515,6 +1515,43 @@ namespace TwkMovie
15151515 return true ;
15161516 }
15171517
1518+ void MovieFFMpegReader::populateTimecodeMetadata (
1519+ const AVDictionaryEntry* tcEntry, const AVTimecode& avTimecode)
1520+ {
1521+ ostringstream tcStart, tcFR, tcFlags;
1522+ tcStart << tcEntry->value << " (" << avTimecode.start << " )" ;
1523+ m_info.proxy .newAttribute (" Timecode/Start" , tcStart.str ());
1524+ tcFR << avTimecode.fps ;
1525+ m_info.proxy .newAttribute (" Timecode/FrameRate" , tcFR.str ());
1526+ if (avTimecode.flags & AV_TIMECODE_FLAG_DROPFRAME)
1527+ {
1528+ tcFlags << " Drop " ;
1529+ }
1530+ if (avTimecode.flags & AV_TIMECODE_FLAG_24HOURSMAX)
1531+ {
1532+ tcFlags << " 24-Hour Max Counter " ;
1533+ }
1534+ if (avTimecode.flags & AV_TIMECODE_FLAG_ALLOWNEGATIVE)
1535+ {
1536+ tcFlags << " Allow Negative" ;
1537+ }
1538+ m_info.proxy .newAttribute (" Timecode/Flags" , tcFlags.str ());
1539+ }
1540+
1541+ AVRational
1542+ MovieFFMpegReader::getTimecodeRate (AVStream* tsStream,
1543+ AVFormatContext* formatContext)
1544+ {
1545+ AVRational tcRate = {tsStream->time_base .den , tsStream->time_base .num };
1546+
1547+ if (isMOVformat (formatContext))
1548+ {
1549+ tcRate = tsStream->avg_frame_rate ;
1550+ }
1551+
1552+ return tcRate;
1553+ }
1554+
15181555 int64_t MovieFFMpegReader::getFirstFrame (AVRational rate)
15191556 {
15201557 //
@@ -1531,17 +1568,11 @@ namespace TwkMovie
15311568 / double (AV_TIME_BASE)));
15321569 int64_t firstFrame = max (int64_t (m_formatStartFrame), int64_t (1 ));
15331570
1571+ bool foundTimecode = false ;
15341572 for (int i = 0 ; i < m_avFormatContext->nb_streams ; i++)
15351573 {
15361574 AVStream* tsStream = m_avFormatContext->streams [i];
1537-
1538- AVRational tcRate = {tsStream->time_base .den ,
1539- tsStream->time_base .num };
1540-
1541- if (isMOVformat (m_avFormatContext))
1542- {
1543- tcRate = tsStream->avg_frame_rate ;
1544- }
1575+ AVRational tcRate = getTimecodeRate (tsStream, m_avFormatContext);
15451576
15461577 AVDictionaryEntry* tcrEntry;
15471578 tcrEntry = av_dict_get (tsStream->metadata , " reel_name" , NULL , 0 );
@@ -1566,29 +1597,37 @@ namespace TwkMovie
15661597 AVTimecode avTimecode;
15671598 av_timecode_init_from_string (&avTimecode, tcRate,
15681599 tcEntry->value , m_avFormatContext);
1569-
15701600 // Add the timecode attributes to the movie info
1571- ostringstream tcStart, tcFR, tcFlags;
1572- tcStart << tcEntry->value << " (" << avTimecode.start << " )" ;
1573- m_info.proxy .newAttribute (" Timecode/Start" , tcStart.str ());
1574- tcFR << avTimecode.fps ;
1575- m_info.proxy .newAttribute (" Timecode/FrameRate" , tcFR.str ());
1576- if (avTimecode.flags & AV_TIMECODE_FLAG_DROPFRAME)
1577- {
1578- tcFlags << " Drop " ;
1579- }
1580- if (avTimecode.flags & AV_TIMECODE_FLAG_24HOURSMAX)
1581- {
1582- tcFlags << " 24-Hour Max Counter " ;
1583- }
1584- if (avTimecode.flags & AV_TIMECODE_FLAG_ALLOWNEGATIVE)
1585- {
1586- tcFlags << " Allow Negative" ;
1587- }
1588- m_info.proxy .newAttribute (" Timecode/Flags" , tcFlags.str ());
1601+ populateTimecodeMetadata (tcEntry, avTimecode);
15891602 m_timecodeTrack = i;
1603+ firstFrame = avTimecode.start ;
1604+ foundTimecode = true ;
1605+ }
1606+ }
15901607
1608+ // Fallback: check format-level metadata for timecode if not found in
1609+ // any stream
1610+ if (!foundTimecode && m_avFormatContext->metadata )
1611+ {
1612+ AVDictionaryEntry* fmtTcEntry =
1613+ av_dict_get (m_avFormatContext->metadata , " timecode" , NULL , 0 );
1614+ if (fmtTcEntry && fmtTcEntry->value )
1615+ {
1616+ // Try to get a valid frame rate the same way as the standard
1617+ // mechanism above.
1618+ AVRational tcRate = {24 , 1 }; // Default to 24fps
1619+ for (unsigned int s = 0 ; s < m_avFormatContext->nb_streams ; ++s)
1620+ {
1621+ AVStream* tsStream = m_avFormatContext->streams [s];
1622+ tcRate = getTimecodeRate (tsStream, m_avFormatContext);
1623+ }
1624+ AVTimecode avTimecode;
1625+ av_timecode_init_from_string (
1626+ &avTimecode, tcRate, fmtTcEntry->value , m_avFormatContext);
1627+ // Add the timecode attributes to the movie info
1628+ populateTimecodeMetadata (fmtTcEntry, avTimecode);
15911629 firstFrame = avTimecode.start ;
1630+ foundTimecode = true ;
15921631 }
15931632 }
15941633 return firstFrame;
0 commit comments