blob: 0d0d6c20967ecc717fe2227b0eee5b9b5c3bf322 [file] [log] [blame]
Andreas Huber1bd994982010-11-09 08:57:45 -08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "include/XINGSeeker.h"
18
19#include <media/stagefright/DataSource.h>
20#include <media/stagefright/Utils.h>
21
22namespace android {
23
24static bool parse_xing_header(
James Dongb1262a82010-11-16 14:04:54 -080025 const sp<DataSource> &source, off64_t first_frame_pos,
Andreas Huber1bd994982010-11-09 08:57:45 -080026 int32_t *frame_number = NULL, int32_t *byte_number = NULL,
27 char *table_of_contents = NULL, int32_t *quality_indicator = NULL,
28 int64_t *duration = NULL);
29
30// static
31sp<XINGSeeker> XINGSeeker::CreateFromSource(
James Dongb1262a82010-11-16 14:04:54 -080032 const sp<DataSource> &source, off64_t first_frame_pos) {
Andreas Huber1bd994982010-11-09 08:57:45 -080033 sp<XINGSeeker> seeker = new XINGSeeker;
34
35 seeker->mFirstFramePos = first_frame_pos;
36
37 if (!parse_xing_header(
38 source, first_frame_pos,
39 NULL, &seeker->mSizeBytes, seeker->mTableOfContents,
40 NULL, &seeker->mDurationUs)) {
41 return NULL;
42 }
43
Andreas Huber1bd994982010-11-09 08:57:45 -080044 return seeker;
45}
46
47XINGSeeker::XINGSeeker()
48 : mDurationUs(-1),
49 mSizeBytes(0) {
50}
51
52bool XINGSeeker::getDuration(int64_t *durationUs) {
53 if (mDurationUs < 0) {
54 return false;
55 }
56
57 *durationUs = mDurationUs;
58
59 return true;
60}
61
James Dongb1262a82010-11-16 14:04:54 -080062bool XINGSeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) {
Andreas Huber1bd994982010-11-09 08:57:45 -080063 if (mSizeBytes == 0 || mTableOfContents[0] <= 0 || mDurationUs < 0) {
64 return false;
65 }
66
67 float percent = (float)(*timeUs) * 100 / mDurationUs;
68 float fx;
69 if( percent <= 0.0f ) {
70 fx = 0.0f;
71 } else if( percent >= 100.0f ) {
72 fx = 256.0f;
73 } else {
74 int a = (int)percent;
75 float fa, fb;
76 if ( a == 0 ) {
77 fa = 0.0f;
78 } else {
79 fa = (float)mTableOfContents[a-1];
80 }
81 if ( a < 99 ) {
82 fb = (float)mTableOfContents[a];
83 } else {
84 fb = 256.0f;
85 }
86 fx = fa + (fb-fa)*(percent-a);
87 }
88
89 *pos = (int)((1.0f/256.0f)*fx*mSizeBytes) + mFirstFramePos;
90
91 return true;
92}
93
94static bool parse_xing_header(
James Dongb1262a82010-11-16 14:04:54 -080095 const sp<DataSource> &source, off64_t first_frame_pos,
Andreas Huber1bd994982010-11-09 08:57:45 -080096 int32_t *frame_number, int32_t *byte_number,
97 char *table_of_contents, int32_t *quality_indicator,
98 int64_t *duration) {
99 if (frame_number) {
100 *frame_number = 0;
101 }
102 if (byte_number) {
103 *byte_number = 0;
104 }
105 if (table_of_contents) {
106 table_of_contents[0] = 0;
107 }
108 if (quality_indicator) {
109 *quality_indicator = 0;
110 }
111 if (duration) {
112 *duration = 0;
113 }
114
115 uint8_t buffer[4];
116 int offset = first_frame_pos;
117 if (source->readAt(offset, &buffer, 4) < 4) { // get header
118 return false;
119 }
120 offset += 4;
121
122 uint8_t id, layer, sr_index, mode;
123 layer = (buffer[1] >> 1) & 3;
124 id = (buffer[1] >> 3) & 3;
125 sr_index = (buffer[2] >> 2) & 3;
126 mode = (buffer[3] >> 6) & 3;
127 if (layer == 0) {
128 return false;
129 }
130 if (id == 1) {
131 return false;
132 }
133 if (sr_index == 3) {
134 return false;
135 }
136 // determine offset of XING header
137 if(id&1) { // mpeg1
138 if (mode != 3) offset += 32;
139 else offset += 17;
140 } else { // mpeg2
141 if (mode != 3) offset += 17;
142 else offset += 9;
143 }
144
145 if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID
146 return false;
147 }
148 offset += 4;
149 // Check XING ID
150 if ((buffer[0] != 'X') || (buffer[1] != 'i')
151 || (buffer[2] != 'n') || (buffer[3] != 'g')) {
152 if ((buffer[0] != 'I') || (buffer[1] != 'n')
153 || (buffer[2] != 'f') || (buffer[3] != 'o')) {
154 return false;
155 }
156 }
157
158 if (source->readAt(offset, &buffer, 4) < 4) { // flags
159 return false;
160 }
161 offset += 4;
162 uint32_t flags = U32_AT(buffer);
163
164 if (flags & 0x0001) { // Frames field is present
165 if (source->readAt(offset, buffer, 4) < 4) {
166 return false;
167 }
168 if (frame_number) {
169 *frame_number = U32_AT(buffer);
170 }
171 int32_t frame = U32_AT(buffer);
172 // Samples per Frame: 1. index = MPEG Version ID, 2. index = Layer
173 const int samplesPerFrames[2][3] =
174 {
175 { 384, 1152, 576 }, // MPEG 2, 2.5: layer1, layer2, layer3
176 { 384, 1152, 1152 }, // MPEG 1: layer1, layer2, layer3
177 };
178 // sampling rates in hertz: 1. index = MPEG Version ID, 2. index = sampling rate index
179 const int samplingRates[4][3] =
180 {
181 { 11025, 12000, 8000, }, // MPEG 2.5
182 { 0, 0, 0, }, // reserved
183 { 22050, 24000, 16000, }, // MPEG 2
184 { 44100, 48000, 32000, } // MPEG 1
185 };
186 if (duration) {
187 *duration = (int64_t)frame * samplesPerFrames[id&1][3-layer] * 1000000LL
188 / samplingRates[id][sr_index];
189 }
190 offset += 4;
191 }
192 if (flags & 0x0002) { // Bytes field is present
193 if (byte_number) {
194 if (source->readAt(offset, buffer, 4) < 4) {
195 return false;
196 }
197 *byte_number = U32_AT(buffer);
198 }
199 offset += 4;
200 }
201 if (flags & 0x0004) { // TOC field is present
202 if (table_of_contents) {
203 if (source->readAt(offset + 1, table_of_contents, 99) < 99) {
204 return false;
205 }
206 }
207 offset += 100;
208 }
209 if (flags & 0x0008) { // Quality indicator field is present
210 if (quality_indicator) {
211 if (source->readAt(offset, buffer, 4) < 4) {
212 return false;
213 }
214 *quality_indicator = U32_AT(buffer);
215 }
216 }
217 return true;
218}
219
220} // namespace android
221