/src/vlc/modules/demux/ogg_granule.c
Line | Count | Source |
1 | | /***************************************************************************** |
2 | | * ogg_granule.c : ogg granule functions |
3 | | ***************************************************************************** |
4 | | * Copyright (C) 2008 - 2018 VideoLAN Authors and VideoLabs |
5 | | * |
6 | | * This program is free software; you can redistribute it and/or modify it |
7 | | * under the terms of the GNU Lesser General Public License as published by |
8 | | * the Free Software Foundation; either version 2.1 of the License, or |
9 | | * (at your option) any later version. |
10 | | * |
11 | | * This program is distributed in the hope that it will be useful, |
12 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14 | | * GNU Lesser General Public License for more details. |
15 | | * |
16 | | * You should have received a copy of the GNU Lesser General Public License |
17 | | * along with this program; if not, write to the Free Software Foundation, |
18 | | * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. |
19 | | *****************************************************************************/ |
20 | | #ifdef HAVE_CONFIG_H |
21 | | # include "config.h" |
22 | | #endif |
23 | | |
24 | | #ifdef HAVE_LIBVORBIS |
25 | | #include <vorbis/codec.h> |
26 | | #endif |
27 | | |
28 | | #include <ogg/ogg.h> |
29 | | |
30 | | #include <vlc_common.h> |
31 | | #include <vlc_codecs.h> |
32 | | #include <vlc_es.h> |
33 | | |
34 | | #include "ogg.h" |
35 | | #include "ogg_granule.h" |
36 | | |
37 | | /* Theora spec 7.1 */ |
38 | 104k | #define THEORA_FTYPE_NOTDATA 0x80 |
39 | 93.4k | #define THEORA_FTYPE_INTERFRAME 0x40 |
40 | | |
41 | | /* Checks if current packet matches codec keyframe */ |
42 | | bool Ogg_IsKeyFrame( const logical_stream_t *p_stream, const ogg_packet *p_packet ) |
43 | 205k | { |
44 | 205k | if ( p_stream->b_oggds ) |
45 | 0 | { |
46 | 0 | return ( p_packet->bytes > 0 && p_packet->packet[0] & PACKET_IS_SYNCPOINT ); |
47 | 0 | } |
48 | 205k | else switch ( p_stream->fmt.i_codec ) |
49 | 205k | { |
50 | 109k | case VLC_CODEC_THEORA: |
51 | 109k | case VLC_CODEC_DAALA: /* Same convention used in daala */ |
52 | 109k | if ( p_packet->bytes <= 0 || p_packet->packet[0] & THEORA_FTYPE_NOTDATA ) |
53 | 15.6k | return false; |
54 | 93.4k | else |
55 | 93.4k | return !( p_packet->packet[0] & THEORA_FTYPE_INTERFRAME ); |
56 | 2.36k | case VLC_CODEC_VP8: |
57 | 2.36k | return ( ( ( p_packet->granulepos >> 3 ) & 0x07FFFFFF ) == 0 ); |
58 | 93.7k | case VLC_CODEC_DIRAC: |
59 | 93.7k | if( p_stream->special.dirac.b_old ) |
60 | 10.0k | return (p_packet->granulepos & 0x3FFFFFFF) == 0; |
61 | 83.6k | else |
62 | 83.6k | return (p_packet->granulepos & 0xFF8000FF) == 0; |
63 | 0 | default: |
64 | 0 | return true; |
65 | 205k | } |
66 | 205k | } |
67 | | |
68 | | int64_t Ogg_GetKeyframeGranule( const logical_stream_t *p_stream, int64_t i_granule ) |
69 | 0 | { |
70 | 0 | if ( p_stream->b_oggds ) |
71 | 0 | { |
72 | 0 | return -1; /* We have no way to know */ |
73 | 0 | } |
74 | 0 | else switch( p_stream->fmt.i_codec ) |
75 | 0 | { |
76 | 0 | case VLC_CODEC_THEORA: |
77 | 0 | case VLC_CODEC_DAALA: |
78 | 0 | return ( i_granule >> p_stream->i_granule_shift ) << p_stream->i_granule_shift; |
79 | 0 | case VLC_CODEC_DIRAC: |
80 | 0 | if( p_stream->special.dirac.b_old ) |
81 | 0 | return ( i_granule >> 30 ) << 30; |
82 | 0 | else |
83 | 0 | return ( i_granule >> 31 ) << 31; |
84 | 0 | default: |
85 | | /* No change, that's keyframe */ |
86 | 0 | return i_granule; |
87 | 0 | } |
88 | 0 | } |
89 | | |
90 | | static int64_t Ogg_GranuleToSampleDelta( const logical_stream_t *p_stream, int64_t i_granule ) |
91 | 2.81k | { |
92 | 2.81k | if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC && !p_stream->special.dirac.b_old ) |
93 | 2.36k | return (i_granule >> 9) & 0x1fff; |
94 | 455 | else |
95 | 455 | return -1; |
96 | 2.81k | } |
97 | | |
98 | | static int64_t Ogg_GranuleToSample( const logical_stream_t *p_stream, int64_t i_granule ) |
99 | 245k | { |
100 | 245k | switch( p_stream->fmt.i_codec ) |
101 | 245k | { |
102 | 166k | case VLC_CODEC_THEORA: |
103 | 166k | if( p_stream->i_first_frame_index == 0 && !p_stream->b_oggds ) |
104 | 160k | i_granule++; |
105 | | /* fallthrough */ |
106 | 166k | case VLC_CODEC_DAALA: |
107 | 166k | case VLC_CODEC_KATE: |
108 | 166k | { |
109 | 166k | ogg_int64_t iframe = i_granule >> p_stream->i_granule_shift; |
110 | 166k | ogg_int64_t pframe = i_granule - ( iframe << p_stream->i_granule_shift ); |
111 | 166k | return iframe + pframe; |
112 | 166k | } |
113 | 382 | case VLC_CODEC_VP8: |
114 | 382 | case VLC_CODEC_OGGSPOTS: |
115 | 382 | return i_granule >> p_stream->i_granule_shift; |
116 | 12.1k | case VLC_CODEC_DIRAC: |
117 | 12.1k | if( p_stream->special.dirac.b_old ) |
118 | 1.96k | return (i_granule >> 30) + (i_granule & 0x3FFFFFFF); |
119 | 10.1k | else |
120 | 10.1k | return (i_granule >> 31); |
121 | 14.1k | case VLC_CODEC_OPUS: |
122 | 58.0k | case VLC_CODEC_VORBIS: |
123 | 60.0k | case VLC_CODEC_SPEEX: |
124 | 60.4k | case VLC_CODEC_FLAC: |
125 | 60.4k | return i_granule/* - p_stream->i_pre_skip*/; |
126 | 6.17k | default: |
127 | 6.17k | return i_granule; |
128 | 245k | } |
129 | 245k | } |
130 | | |
131 | | static int64_t Ogg_ShiftPacketSample( const logical_stream_t *p_stream, |
132 | | int64_t i_sample, bool b_start ) |
133 | 245k | { |
134 | | /* /!\ Packet Granule as sample value ! */ |
135 | | |
136 | | /* granule always point to end time of packet |
137 | | Except with OggDS where it is reversed */ |
138 | 245k | int64_t i_endtostartoffset = 0; /* in interval # */ |
139 | 245k | if( p_stream->b_oggds ) |
140 | 6.17k | i_endtostartoffset = (b_start ? 0 : 1); |
141 | 239k | else |
142 | 239k | i_endtostartoffset = (b_start ? -1 : 0); |
143 | | |
144 | 245k | if( p_stream->fmt.i_cat == VIDEO_ES ) |
145 | 179k | { |
146 | 179k | if( p_stream->fmt.i_codec == VLC_CODEC_DIRAC ) /* points to start */ |
147 | 12.1k | i_sample += (p_stream->special.dirac.b_interlaced ? 1 : 2) * (i_endtostartoffset + 1); |
148 | 167k | else |
149 | 167k | i_sample += i_endtostartoffset * 1; |
150 | 179k | } |
151 | 66.5k | else if( p_stream->fmt.i_cat == AUDIO_ES ) |
152 | 60.4k | { |
153 | 60.4k | if( p_stream->fmt.i_codec == VLC_CODEC_SPEEX ) |
154 | 2.02k | { |
155 | 2.02k | i_sample += i_endtostartoffset * |
156 | 2.02k | p_stream->special.speex.i_framesize * |
157 | 2.02k | p_stream->special.speex.i_framesperpacket; |
158 | 2.02k | } |
159 | 58.3k | else /* we can't tell */ |
160 | 58.3k | { |
161 | 58.3k | if( i_endtostartoffset != 0 ) |
162 | 15.7k | return -1; |
163 | 58.3k | } |
164 | 60.4k | } |
165 | 230k | return i_sample; |
166 | 245k | } |
167 | | |
168 | | vlc_tick_t Ogg_SampleToTime( const logical_stream_t *p_stream, int64_t i_sample, bool b_start ) |
169 | 245k | { |
170 | 245k | i_sample = Ogg_ShiftPacketSample( p_stream, i_sample, b_start ); |
171 | 245k | if( i_sample < 0 ) |
172 | 16.2k | return VLC_TICK_INVALID; |
173 | | |
174 | 229k | date_t d = p_stream->dts; |
175 | 229k | date_Set(&d, VLC_TICK_0); |
176 | 229k | return date_Increment( &d, i_sample ); |
177 | 245k | } |
178 | | |
179 | | bool Ogg_GranuleIsValid( const logical_stream_t *p_stream, int64_t i_granule ) |
180 | 4.41M | { |
181 | | /* First frame in ogm is 0 (0[header] 0[frame] -1 2 3 -1 5 ...) */ |
182 | 4.41M | return !( i_granule < p_stream->i_first_frame_index - !!p_stream->b_oggds ); |
183 | 4.41M | } |
184 | | |
185 | | vlc_tick_t Ogg_GranuleToTime( const logical_stream_t *p_stream, int64_t i_granule, |
186 | | bool b_start, bool b_pts ) |
187 | 3.02M | { |
188 | 3.02M | if( !Ogg_GranuleIsValid( p_stream, i_granule ) ) |
189 | 2.78M | return VLC_TICK_INVALID; |
190 | | |
191 | 245k | int64_t i_sample = Ogg_GranuleToSample( p_stream, i_granule ); |
192 | 245k | if( b_pts ) |
193 | 2.81k | { |
194 | 2.81k | int64_t i_delta = Ogg_GranuleToSampleDelta( p_stream, i_granule ); |
195 | 2.81k | if( i_delta != -1 ) |
196 | 2.36k | i_sample += i_delta; |
197 | 2.81k | } |
198 | 245k | return Ogg_SampleToTime( p_stream, i_sample, b_start ); |
199 | 3.02M | } |