1 /*
2 * ISO File Format parsing library
3 *
4 * gstisoff.h
5 *
6 * Copyright (C) 2015 Samsung Electronics. All rights reserved.
7 * Author: Thiago Santos <thiagoss@osg.samsung.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library (COPYING); if not, write to the
21 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22 * Boston, MA 02111-1307, USA.
23 */
24
25 #include "qtdemux_debug.h"
26 #include "gstisoff.h"
27 #include <gst/base/gstbytereader.h>
28
29 #define GST_CAT_DEFAULT qtdemux_debug
30
31 void
gst_isoff_qt_sidx_parser_init(GstSidxParser * parser)32 gst_isoff_qt_sidx_parser_init (GstSidxParser * parser)
33 {
34 parser->status = GST_ISOFF_QT_SIDX_PARSER_INIT;
35 parser->cumulative_entry_size = 0;
36 parser->sidx.entries = NULL;
37 parser->sidx.entries_count = 0;
38 }
39
40 void
gst_isoff_qt_sidx_parser_clear(GstSidxParser * parser)41 gst_isoff_qt_sidx_parser_clear (GstSidxParser * parser)
42 {
43 g_free (parser->sidx.entries);
44 parser->sidx.entries = NULL;
45 }
46
47 static void
gst_isoff_qt_parse_sidx_entry(GstSidxBoxEntry * entry,GstByteReader * reader)48 gst_isoff_qt_parse_sidx_entry (GstSidxBoxEntry * entry, GstByteReader * reader)
49 {
50 guint32 aux;
51
52 aux = gst_byte_reader_get_uint32_be_unchecked (reader);
53 entry->ref_type = aux >> 31;
54 entry->size = aux & 0x7FFFFFFF;
55 entry->duration = gst_byte_reader_get_uint32_be_unchecked (reader);
56 aux = gst_byte_reader_get_uint32_be_unchecked (reader);
57 entry->starts_with_sap = aux >> 31;
58 entry->sap_type = ((aux >> 28) & 0x7);
59 entry->sap_delta_time = aux & 0xFFFFFFF;
60 }
61
62 GstIsoffParserResult
gst_isoff_qt_sidx_parser_add_data(GstSidxParser * parser,const guint8 * buffer,gint length,guint * consumed)63 gst_isoff_qt_sidx_parser_add_data (GstSidxParser * parser,
64 const guint8 * buffer, gint length, guint * consumed)
65 {
66 GstIsoffParserResult res = GST_ISOFF_QT_PARSER_OK;
67 GstByteReader reader;
68 gsize remaining;
69 guint32 fourcc;
70
71 gst_byte_reader_init (&reader, buffer, length);
72
73 switch (parser->status) {
74 case GST_ISOFF_QT_SIDX_PARSER_INIT:
75 if (gst_byte_reader_get_remaining (&reader) < GST_ISOFF_QT_FULL_BOX_SIZE) {
76 break;
77 }
78
79 parser->size = gst_byte_reader_get_uint32_be_unchecked (&reader);
80 fourcc = gst_byte_reader_get_uint32_le_unchecked (&reader);
81 if (fourcc != GST_ISOFF_QT_FOURCC_SIDX) {
82 res = GST_ISOFF_QT_PARSER_UNEXPECTED;
83 gst_byte_reader_set_pos (&reader, 0);
84 break;
85 }
86 if (parser->size == 1) {
87 if (gst_byte_reader_get_remaining (&reader) < 12) {
88 gst_byte_reader_set_pos (&reader, 0);
89 break;
90 }
91
92 parser->size = gst_byte_reader_get_uint64_be_unchecked (&reader);
93 }
94 if (parser->size == 0) {
95 res = GST_ISOFF_QT_PARSER_ERROR;
96 gst_byte_reader_set_pos (&reader, 0);
97 break;
98 }
99 parser->sidx.version = gst_byte_reader_get_uint8_unchecked (&reader);
100 parser->sidx.flags = gst_byte_reader_get_uint24_le_unchecked (&reader);
101
102 parser->status = GST_ISOFF_QT_SIDX_PARSER_HEADER;
103
104 case GST_ISOFF_QT_SIDX_PARSER_HEADER:
105 remaining = gst_byte_reader_get_remaining (&reader);
106 if (remaining < 12 + (parser->sidx.version == 0 ? 8 : 16)) {
107 break;
108 }
109
110 parser->sidx.ref_id = gst_byte_reader_get_uint32_be_unchecked (&reader);
111 parser->sidx.timescale =
112 gst_byte_reader_get_uint32_be_unchecked (&reader);
113 if (parser->sidx.version == 0) {
114 parser->sidx.earliest_pts =
115 gst_byte_reader_get_uint32_be_unchecked (&reader);
116 parser->sidx.first_offset = parser->sidx.earliest_pts =
117 gst_byte_reader_get_uint32_be_unchecked (&reader);
118 } else {
119 parser->sidx.earliest_pts =
120 gst_byte_reader_get_uint64_be_unchecked (&reader);
121 parser->sidx.first_offset =
122 gst_byte_reader_get_uint64_be_unchecked (&reader);
123 }
124 /* skip 2 reserved bytes */
125 gst_byte_reader_skip_unchecked (&reader, 2);
126 parser->sidx.entries_count =
127 gst_byte_reader_get_uint16_be_unchecked (&reader);
128
129 GST_LOG ("Timescale: %" G_GUINT32_FORMAT, parser->sidx.timescale);
130 GST_LOG ("Earliest pts: %" G_GUINT64_FORMAT, parser->sidx.earliest_pts);
131 GST_LOG ("First offset: %" G_GUINT64_FORMAT, parser->sidx.first_offset);
132
133 parser->cumulative_pts =
134 gst_util_uint64_scale_int_round (parser->sidx.earliest_pts,
135 GST_SECOND, parser->sidx.timescale);
136
137 if (parser->sidx.entries_count) {
138 parser->sidx.entries =
139 g_malloc (sizeof (GstSidxBoxEntry) * parser->sidx.entries_count);
140 }
141 parser->sidx.entry_index = 0;
142
143 parser->status = GST_ISOFF_QT_SIDX_PARSER_DATA;
144
145 case GST_ISOFF_QT_SIDX_PARSER_DATA:
146 while (parser->sidx.entry_index < parser->sidx.entries_count) {
147 GstSidxBoxEntry *entry =
148 &parser->sidx.entries[parser->sidx.entry_index];
149
150 remaining = gst_byte_reader_get_remaining (&reader);
151 if (remaining < 12)
152 break;
153
154 entry->offset = parser->cumulative_entry_size;
155 entry->pts = parser->cumulative_pts;
156 gst_isoff_qt_parse_sidx_entry (entry, &reader);
157 entry->duration = gst_util_uint64_scale_int_round (entry->duration,
158 GST_SECOND, parser->sidx.timescale);
159 parser->cumulative_entry_size += entry->size;
160 parser->cumulative_pts += entry->duration;
161
162 GST_LOG ("Sidx entry %d) offset: %" G_GUINT64_FORMAT ", pts: %"
163 GST_TIME_FORMAT ", duration %" GST_TIME_FORMAT " - size %"
164 G_GUINT32_FORMAT, parser->sidx.entry_index, entry->offset,
165 GST_TIME_ARGS (entry->pts), GST_TIME_ARGS (entry->duration),
166 entry->size);
167
168 parser->sidx.entry_index++;
169 }
170
171 if (parser->sidx.entry_index == parser->sidx.entries_count)
172 parser->status = GST_ISOFF_QT_SIDX_PARSER_FINISHED;
173 else
174 break;
175 case GST_ISOFF_QT_SIDX_PARSER_FINISHED:
176 parser->sidx.entry_index = 0;
177 res = GST_ISOFF_QT_PARSER_DONE;
178 break;
179 }
180
181 *consumed = gst_byte_reader_get_pos (&reader);
182 return res;
183 }
184
185 GstIsoffParserResult
gst_isoff_qt_sidx_parser_add_buffer(GstSidxParser * parser,GstBuffer * buffer,guint * consumed)186 gst_isoff_qt_sidx_parser_add_buffer (GstSidxParser * parser, GstBuffer * buffer,
187 guint * consumed)
188 {
189 GstIsoffParserResult res = GST_ISOFF_QT_PARSER_OK;
190 GstMapInfo info;
191
192 if (!gst_buffer_map (buffer, &info, GST_MAP_READ)) {
193 *consumed = 0;
194 return GST_ISOFF_QT_PARSER_ERROR;
195 }
196
197 res =
198 gst_isoff_qt_sidx_parser_add_data (parser, info.data, info.size,
199 consumed);
200
201 gst_buffer_unmap (buffer, &info);
202 return res;
203 }
204