Commit 3111f292 authored by Francois Cartegnie's avatar Francois Cartegnie

demux: ogg: add ogg/VP8 support

parent 8584fc6e
...@@ -37,6 +37,7 @@ Demuxer: ...@@ -37,6 +37,7 @@ Demuxer:
* Support microseconds in SubRip subtitles * Support microseconds in SubRip subtitles
* FLAC packets validation using CRC * FLAC packets validation using CRC
* Support Opus in MKV * Support Opus in MKV
* Support VP8 in OGG
* Basic support for WebVTT * Basic support for WebVTT
* Handle support for ISO/IEC 14496-3 Audio stream type in TS * Handle support for ISO/IEC 14496-3 Audio stream type in TS
* Support HDPR TS files * Support HDPR TS files
......
...@@ -137,6 +137,7 @@ static void Ogg_ReadKateHeader( logical_stream_t *, ogg_packet * ); ...@@ -137,6 +137,7 @@ static void Ogg_ReadKateHeader( logical_stream_t *, ogg_packet * );
static void Ogg_ReadFlacHeader( demux_t *, logical_stream_t *, ogg_packet * ); static void Ogg_ReadFlacHeader( demux_t *, logical_stream_t *, ogg_packet * );
static void Ogg_ReadAnnodexHeader( demux_t *, logical_stream_t *, ogg_packet * ); static void Ogg_ReadAnnodexHeader( demux_t *, logical_stream_t *, ogg_packet * );
static bool Ogg_ReadDiracHeader( logical_stream_t *, ogg_packet * ); static bool Ogg_ReadDiracHeader( logical_stream_t *, ogg_packet * );
static bool Ogg_ReadVP8Header( demux_t *, logical_stream_t *, ogg_packet * );
static void Ogg_ReadSkeletonHeader( demux_t *, logical_stream_t *, ogg_packet * ); static void Ogg_ReadSkeletonHeader( demux_t *, logical_stream_t *, ogg_packet * );
/* Skeleton */ /* Skeleton */
...@@ -490,6 +491,7 @@ static int Demux( demux_t * p_demux ) ...@@ -490,6 +491,7 @@ static int Demux( demux_t * p_demux )
if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS || if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
p_stream->fmt.i_codec == VLC_CODEC_SPEEX || p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
p_stream->fmt.i_codec == VLC_CODEC_OPUS || p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
p_stream->fmt.i_codec == VLC_CODEC_VP8 ||
p_stream->fmt.i_codec == VLC_CODEC_FLAC ) p_stream->fmt.i_codec == VLC_CODEC_FLAC )
{ {
if( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 ) if( ogg_stream_packetout( &p_stream->os, &oggpacket ) > 0 )
...@@ -862,6 +864,7 @@ static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream, ...@@ -862,6 +864,7 @@ static void Ogg_UpdatePCR( demux_t *p_demux, logical_stream_t *p_stream,
{ {
if( p_stream->fmt.i_codec == VLC_CODEC_THEORA || if( p_stream->fmt.i_codec == VLC_CODEC_THEORA ||
p_stream->fmt.i_codec == VLC_CODEC_KATE || p_stream->fmt.i_codec == VLC_CODEC_KATE ||
p_stream->fmt.i_codec == VLC_CODEC_VP8 ||
p_stream->fmt.i_codec == VLC_CODEC_DIRAC ) p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
{ {
p_stream->i_pcr = Oggseek_GranuleToAbsTimestamp( p_stream, p_stream->i_pcr = Oggseek_GranuleToAbsTimestamp( p_stream,
...@@ -973,6 +976,13 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -973,6 +976,13 @@ static void Ogg_DecodePacket( demux_t *p_demux,
Ogg_ReadSkeletonIndex( p_demux, p_oggpacket ); Ogg_ReadSkeletonIndex( p_demux, p_oggpacket );
return; return;
} }
else if( p_stream->fmt.i_codec == VLC_CODEC_VP8 &&
p_oggpacket->bytes >= 7 &&
!memcmp( p_oggpacket->packet, "OVP80\x02\x20", 7 ) )
{
Ogg_ReadVP8Header( p_demux, p_stream, p_oggpacket );
return;
}
if( p_stream->fmt.i_codec == VLC_CODEC_SUBT && p_oggpacket->bytes > 0 && if( p_stream->fmt.i_codec == VLC_CODEC_SUBT && p_oggpacket->bytes > 0 &&
p_oggpacket->packet[0] & PACKET_TYPE_BITS ) return; p_oggpacket->packet[0] & PACKET_TYPE_BITS ) return;
...@@ -1097,6 +1107,7 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -1097,6 +1107,7 @@ static void Ogg_DecodePacket( demux_t *p_demux,
if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS || if( p_stream->fmt.i_codec == VLC_CODEC_VORBIS ||
p_stream->fmt.i_codec == VLC_CODEC_SPEEX || p_stream->fmt.i_codec == VLC_CODEC_SPEEX ||
p_stream->fmt.i_codec == VLC_CODEC_OPUS || p_stream->fmt.i_codec == VLC_CODEC_OPUS ||
p_stream->fmt.i_codec == VLC_CODEC_VP8 ||
p_stream->fmt.i_codec == VLC_CODEC_FLAC ) p_stream->fmt.i_codec == VLC_CODEC_FLAC )
{ {
if( p_stream->i_pcr > VLC_TS_INVALID ) if( p_stream->i_pcr > VLC_TS_INVALID )
...@@ -1114,6 +1125,7 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -1114,6 +1125,7 @@ static void Ogg_DecodePacket( demux_t *p_demux,
if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS && if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS &&
p_stream->fmt.i_codec != VLC_CODEC_SPEEX && p_stream->fmt.i_codec != VLC_CODEC_SPEEX &&
p_stream->fmt.i_codec != VLC_CODEC_OPUS && p_stream->fmt.i_codec != VLC_CODEC_OPUS &&
p_stream->fmt.i_codec != VLC_CODEC_VP8 &&
p_stream->fmt.i_codec != VLC_CODEC_FLAC && p_stream->fmt.i_codec != VLC_CODEC_FLAC &&
p_stream->i_pcr >= 0 ) p_stream->i_pcr >= 0 )
{ {
...@@ -1206,6 +1218,15 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -1206,6 +1218,15 @@ static void Ogg_DecodePacket( demux_t *p_demux,
if( -1 != p_oggpacket->granulepos ) if( -1 != p_oggpacket->granulepos )
p_block->i_pts = u_pnum * CLOCK_FREQ / p_stream->f_rate / 2; p_block->i_pts = u_pnum * CLOCK_FREQ / p_stream->f_rate / 2;
} }
else if( p_stream->fmt.i_codec == VLC_CODEC_VP8 )
{
p_block->i_pts = p_stream->i_interpolated_pcr;
p_block->i_dts = p_block->i_pts;
if( p_oggpacket->granulepos > 0 && Ogg_IsKeyFrame( p_stream, p_oggpacket ) )
{
p_block->i_flags |= BLOCK_FLAG_TYPE_I;
}
}
else else
{ {
p_block->i_dts = i_pts; p_block->i_dts = i_pts;
...@@ -1215,6 +1236,7 @@ static void Ogg_DecodePacket( demux_t *p_demux, ...@@ -1215,6 +1236,7 @@ static void Ogg_DecodePacket( demux_t *p_demux,
if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS && if( p_stream->fmt.i_codec != VLC_CODEC_VORBIS &&
p_stream->fmt.i_codec != VLC_CODEC_SPEEX && p_stream->fmt.i_codec != VLC_CODEC_SPEEX &&
p_stream->fmt.i_codec != VLC_CODEC_OPUS && p_stream->fmt.i_codec != VLC_CODEC_OPUS &&
p_stream->fmt.i_codec != VLC_CODEC_VP8 &&
p_stream->fmt.i_codec != VLC_CODEC_FLAC && p_stream->fmt.i_codec != VLC_CODEC_FLAC &&
p_stream->fmt.i_codec != VLC_CODEC_TARKIN && p_stream->fmt.i_codec != VLC_CODEC_TARKIN &&
p_stream->fmt.i_codec != VLC_CODEC_THEORA && p_stream->fmt.i_codec != VLC_CODEC_THEORA &&
...@@ -1502,6 +1524,19 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux ) ...@@ -1502,6 +1524,19 @@ static int Ogg_FindLogicalStreams( demux_t *p_demux )
"found tarkin header, bitrate: %i, rate: %f", "found tarkin header, bitrate: %i, rate: %f",
p_stream->fmt.i_bitrate, p_stream->f_rate ); p_stream->fmt.i_bitrate, p_stream->f_rate );
} }
/* Check for VP8 header */
else if( oggpacket.bytes >= 26 &&
! memcmp( oggpacket.packet, "OVP80", 5 ) )
{
if ( Ogg_ReadVP8Header( p_demux, p_stream, &oggpacket ) )
msg_Dbg( p_demux, "found VP8 header "
"fps: %f, width:%i; height:%i",
p_stream->f_rate,
p_stream->fmt.video.i_width,
p_stream->fmt.video.i_height );
else
p_stream->fmt.i_cat = UNKNOWN_ES;
}
/* Check for Annodex header */ /* Check for Annodex header */
else if( oggpacket.bytes >= 7 && else if( oggpacket.bytes >= 7 &&
! memcmp( oggpacket.packet, "Annodex", 7 ) ) ! memcmp( oggpacket.packet, "Annodex", 7 ) )
...@@ -2201,7 +2236,9 @@ static void Ogg_ExtractMeta( demux_t *p_demux, es_format_t *p_fmt, const uint8_t ...@@ -2201,7 +2236,9 @@ static void Ogg_ExtractMeta( demux_t *p_demux, es_format_t *p_fmt, const uint8_t
case VLC_CODEC_SPEEX: case VLC_CODEC_SPEEX:
Ogg_ExtractXiphMeta( p_demux, p_fmt, p_headers, i_headers, 0 ); Ogg_ExtractXiphMeta( p_demux, p_fmt, p_headers, i_headers, 0 );
break; break;
case VLC_CODEC_VP8:
Ogg_ExtractComments( p_demux, p_fmt, p_headers, i_headers );
break;
/* N headers with the 2° one being the comments */ /* N headers with the 2° one being the comments */
case VLC_CODEC_KATE: case VLC_CODEC_KATE:
/* 1 byte for header type, 7 bytes for magic, 1 reserved zero byte */ /* 1 byte for header type, 7 bytes for magic, 1 reserved zero byte */
...@@ -2469,6 +2506,37 @@ static void Ogg_ReadKateHeader( logical_stream_t *p_stream, ...@@ -2469,6 +2506,37 @@ static void Ogg_ReadKateHeader( logical_stream_t *p_stream,
} }
} }
static bool Ogg_ReadVP8Header( demux_t *p_demux, logical_stream_t *p_stream,
ogg_packet *p_oggpacket )
{
switch( p_oggpacket->packet[5] )
{
/* STREAMINFO */
case 0x01:
/* Mapping version */
if ( p_oggpacket->packet[6] != 0x01 || p_oggpacket->packet[7] != 0x00 )
return false;
p_stream->fmt.i_cat = VIDEO_ES;
p_stream->fmt.i_codec = VLC_CODEC_VP8;
p_stream->i_granule_shift = 32;
p_stream->fmt.video.i_width = GetWBE( &p_oggpacket->packet[8] );
p_stream->fmt.video.i_height = GetWBE( &p_oggpacket->packet[10] );
p_stream->fmt.video.i_sar_num = GetDWBE( &p_oggpacket->packet[12 - 1] ) & 0x0FFF;
p_stream->fmt.video.i_sar_den = GetDWBE( &p_oggpacket->packet[15 - 1] ) & 0x0FFF;
p_stream->fmt.video.i_frame_rate = GetDWBE( &p_oggpacket->packet[18] );
p_stream->fmt.video.i_frame_rate_base = GetDWBE( &p_oggpacket->packet[22] );
p_stream->f_rate = (double) p_stream->fmt.video.i_frame_rate / p_stream->fmt.video.i_frame_rate_base;
return true;
/* METADATA */
case 0x02:
Ogg_ExtractMeta( p_demux, & p_stream->fmt,
p_oggpacket->packet + 7, p_oggpacket->bytes - 7 );
return true;
default:
return false;
}
}
static void Ogg_ApplyContentType( logical_stream_t *p_stream, const char* psz_value, static void Ogg_ApplyContentType( logical_stream_t *p_stream, const char* psz_value,
bool *b_force_backup, bool *b_packet_out ) bool *b_force_backup, bool *b_packet_out )
{ {
...@@ -2537,6 +2605,11 @@ static void Ogg_ApplyContentType( logical_stream_t *p_stream, const char* psz_va ...@@ -2537,6 +2605,11 @@ static void Ogg_ApplyContentType( logical_stream_t *p_stream, const char* psz_va
free( p_stream->fmt.psz_description ); free( p_stream->fmt.psz_description );
p_stream->fmt.psz_description = strdup("OGG Kate Overlay (Unsupported)"); p_stream->fmt.psz_description = strdup("OGG Kate Overlay (Unsupported)");
} }
else if( !strncmp(psz_value, "video/x-vp8", 11) )
{
p_stream->fmt.i_cat = VIDEO_ES;
p_stream->fmt.i_codec = VLC_CODEC_VP8;
}
} }
static void Ogg_ReadAnnodexHeader( demux_t *p_demux, static void Ogg_ReadAnnodexHeader( demux_t *p_demux,
......
...@@ -561,6 +561,10 @@ bool Ogg_IsKeyFrame( logical_stream_t *p_stream, ogg_packet *p_packet ) ...@@ -561,6 +561,10 @@ bool Ogg_IsKeyFrame( logical_stream_t *p_stream, ogg_packet *p_packet )
else else
return !( p_packet->packet[0] & THEORA_FTYPE_INTERFRAME ); return !( p_packet->packet[0] & THEORA_FTYPE_INTERFRAME );
} }
else if ( p_stream->fmt.i_codec == VLC_CODEC_VP8 )
{
return ( ( ( p_packet->granulepos >> 3 ) & 0x07FFFFFF ) == 0 );
}
return true; return true;
} }
...@@ -786,6 +790,12 @@ int64_t Oggseek_GranuleToAbsTimestamp( logical_stream_t *p_stream, ...@@ -786,6 +790,12 @@ int64_t Oggseek_GranuleToAbsTimestamp( logical_stream_t *p_stream,
if ( b_presentation ) pframe -= p_stream->i_keyframe_offset; if ( b_presentation ) pframe -= p_stream->i_keyframe_offset;
i_timestamp = ( iframe + pframe ) * CLOCK_FREQ / p_stream->f_rate; i_timestamp = ( iframe + pframe ) * CLOCK_FREQ / p_stream->f_rate;
} }
else if ( p_stream->fmt.i_codec == VLC_CODEC_VP8 )
{
ogg_int64_t frame = i_granule >> p_stream->i_granule_shift;
if ( b_presentation ) frame--;
i_timestamp = frame * CLOCK_FREQ / p_stream->f_rate;
}
else if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC ) else if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC )
{ {
ogg_int64_t i_dts = i_granule >> 31; ogg_int64_t i_dts = i_granule >> 31;
...@@ -825,6 +835,12 @@ bool Oggseek_PacketPCRFixup( logical_stream_t *p_stream, ogg_page *p_page, ...@@ -825,6 +835,12 @@ bool Oggseek_PacketPCRFixup( logical_stream_t *p_stream, ogg_page *p_page,
ogg_page_packets( p_page ) / p_stream->f_rate; ogg_page_packets( p_page ) / p_stream->f_rate;
return true; return true;
} }
else if ( p_stream->fmt.i_codec == VLC_CODEC_VP8 )
{
ogg_int64_t frame = ogg_page_granulepos( p_page ) >> p_stream->i_granule_shift;
frame -= ogg_page_packets( p_page );
p_stream->i_pcr = frame * CLOCK_FREQ / p_stream->f_rate;
}
return false; return false;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment