blob: 616836cbb545dc19237deff00fb050527a183940 [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
44 LOGI("Found XING header.");
45
46 return seeker;
47}
48
49XINGSeeker::XINGSeeker()
50 : mDurationUs(-1),
51 mSizeBytes(0) {
52}
53
54bool XINGSeeker::getDuration(int64_t *durationUs) {
55 if (mDurationUs < 0) {
56 return false;
57 }
58
59 *durationUs = mDurationUs;
60
61 return true;
62}
63
James Dongb1262a82010-11-16 14:04:54 -080064bool XINGSeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) {
Andreas Huber1bd994982010-11-09 08:57:45 -080065 if (mSizeBytes == 0 || mTableOfContents[0] <= 0 || mDurationUs < 0) {
66 return false;
67 }
68
69 float percent = (float)(*timeUs) * 100 / mDurationUs;
70 float fx;
71 if( percent <= 0.0f ) {
72 fx = 0.0f;
73 } else if( percent >= 100.0f ) {
74 fx = 256.0f;
75 } else {
76 int a = (int)percent;
77 float fa, fb;
78 if ( a == 0 ) {
79 fa = 0.0f;
80 } else {
81 fa = (float)mTableOfContents[a-1];
82 }
83 if ( a < 99 ) {
84 fb = (float)mTableOfContents[a];
85 } else {
86 fb = 256.0f;
87 }
88 fx = fa + (fb-fa)*(percent-a);
89 }
90
91 *pos = (int)((1.0f/256.0f)*fx*mSizeBytes) + mFirstFramePos;
92
93 return true;
94}
95
96static bool parse_xing_header(
James Dongb1262a82010-11-16 14:04:54 -080097 const sp<DataSource> &source, off64_t first_frame_pos,
Andreas Huber1bd994982010-11-09 08:57:45 -080098 int32_t *frame_number, int32_t *byte_number,
99 char *table_of_contents, int32_t *quality_indicator,
100 int64_t *duration) {
101 if (frame_number) {
102 *frame_number = 0;
103 }
104 if (byte_number) {
105 *byte_number = 0;
106 }
107 if (table_of_contents) {
108 table_of_contents[0] = 0;
109 }
110 if (quality_indicator) {
111 *quality_indicator = 0;
112 }
113 if (duration) {
114 *duration = 0;
115 }
116
117 uint8_t buffer[4];
118 int offset = first_frame_pos;
119 if (source->readAt(offset, &buffer, 4) < 4) { // get header
120 return false;
121 }
122 offset += 4;
123
124 uint8_t id, layer, sr_index, mode;
125 layer = (buffer[1] >> 1) & 3;
126 id = (buffer[1] >> 3) & 3;
127 sr_index = (buffer[2] >> 2) & 3;
128 mode = (buffer[3] >> 6) & 3;
129 if (layer == 0) {
130 return false;
131 }
132 if (id == 1) {
133 return false;
134 }
135 if (sr_index == 3) {
136 return false;
137 }
138 // determine offset of XING header
139 if(id&1) { // mpeg1
140 if (mode != 3) offset += 32;
141 else offset += 17;
142 } else { // mpeg2
143 if (mode != 3) offset += 17;
144 else offset += 9;
145 }
146
147 if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID
148 return false;
149 }
150 offset += 4;
151 // Check XING ID
152 if ((buffer[0] != 'X') || (buffer[1] != 'i')
153 || (buffer[2] != 'n') || (buffer[3] != 'g')) {
154 if ((buffer[0] != 'I') || (buffer[1] != 'n')
155 || (buffer[2] != 'f') || (buffer[3] != 'o')) {
156 return false;
157 }
158 }
159
160 if (source->readAt(offset, &buffer, 4) < 4) { // flags
161 return false;
162 }
163 offset += 4;
164 uint32_t flags = U32_AT(buffer);
165
166 if (flags & 0x0001) { // Frames field is present
167 if (source->readAt(offset, buffer, 4) < 4) {
168 return false;
169 }
170 if (frame_number) {
171 *frame_number = U32_AT(buffer);
172 }
173 int32_t frame = U32_AT(buffer);
174 // Samples per Frame: 1. index = MPEG Version ID, 2. index = Layer
175 const int samplesPerFrames[2][3] =
176 {
177 { 384, 1152, 576 }, // MPEG 2, 2.5: layer1, layer2, layer3
178 { 384, 1152, 1152 }, // MPEG 1: layer1, layer2, layer3
179 };
180 // sampling rates in hertz: 1. index = MPEG Version ID, 2. index = sampling rate index
181 const int samplingRates[4][3] =
182 {
183 { 11025, 12000, 8000, }, // MPEG 2.5
184 { 0, 0, 0, }, // reserved
185 { 22050, 24000, 16000, }, // MPEG 2
186 { 44100, 48000, 32000, } // MPEG 1
187 };
188 if (duration) {
189 *duration = (int64_t)frame * samplesPerFrames[id&1][3-layer] * 1000000LL
190 / samplingRates[id][sr_index];
191 }
192 offset += 4;
193 }
194 if (flags & 0x0002) { // Bytes field is present
195 if (byte_number) {
196 if (source->readAt(offset, buffer, 4) < 4) {
197 return false;
198 }
199 *byte_number = U32_AT(buffer);
200 }
201 offset += 4;
202 }
203 if (flags & 0x0004) { // TOC field is present
204 if (table_of_contents) {
205 if (source->readAt(offset + 1, table_of_contents, 99) < 99) {
206 return false;
207 }
208 }
209 offset += 100;
210 }
211 if (flags & 0x0008) { // Quality indicator field is present
212 if (quality_indicator) {
213 if (source->readAt(offset, buffer, 4) < 4) {
214 return false;
215 }
216 *quality_indicator = U32_AT(buffer);
217 }
218 }
219 return true;
220}
221
222} // namespace android
223