blob: 9c91134922e7042de9f15fdfa170dc9b236c368d [file] [log] [blame]
Andreas Huber4456da52010-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
Marco Nelissenb636abd2012-03-19 13:49:43 -070017#define LOG_TAG "XINGSEEKER"
18#include <utils/Log.h>
19
Andreas Huber4456da52010-11-09 08:57:45 -080020#include "include/XINGSeeker.h"
Marco Nelissen9e503852012-03-16 07:56:42 -070021#include "include/avc_utils.h"
Andreas Huber4456da52010-11-09 08:57:45 -080022
23#include <media/stagefright/DataSource.h>
24#include <media/stagefright/Utils.h>
25
26namespace android {
27
Andreas Huber4456da52010-11-09 08:57:45 -080028XINGSeeker::XINGSeeker()
29 : mDurationUs(-1),
Marco Nelissenb636abd2012-03-19 13:49:43 -070030 mSizeBytes(0),
31 mEncoderDelay(0),
32 mEncoderPadding(0) {
Andreas Huber4456da52010-11-09 08:57:45 -080033}
34
35bool XINGSeeker::getDuration(int64_t *durationUs) {
36 if (mDurationUs < 0) {
37 return false;
38 }
39
40 *durationUs = mDurationUs;
41
42 return true;
43}
44
James Dongc7fc37a2010-11-16 14:04:54 -080045bool XINGSeeker::getOffsetForTime(int64_t *timeUs, off64_t *pos) {
Marco Nelissen51024002012-03-14 16:40:11 -070046 if (mSizeBytes == 0 || !mTOCValid || mDurationUs < 0) {
Andreas Huber4456da52010-11-09 08:57:45 -080047 return false;
48 }
49
50 float percent = (float)(*timeUs) * 100 / mDurationUs;
51 float fx;
52 if( percent <= 0.0f ) {
53 fx = 0.0f;
54 } else if( percent >= 100.0f ) {
55 fx = 256.0f;
56 } else {
57 int a = (int)percent;
58 float fa, fb;
59 if ( a == 0 ) {
60 fa = 0.0f;
61 } else {
Marco Nelissen51024002012-03-14 16:40:11 -070062 fa = (float)mTOC[a-1];
Andreas Huber4456da52010-11-09 08:57:45 -080063 }
64 if ( a < 99 ) {
Marco Nelissen51024002012-03-14 16:40:11 -070065 fb = (float)mTOC[a];
Andreas Huber4456da52010-11-09 08:57:45 -080066 } else {
67 fb = 256.0f;
68 }
69 fx = fa + (fb-fa)*(percent-a);
70 }
71
72 *pos = (int)((1.0f/256.0f)*fx*mSizeBytes) + mFirstFramePos;
73
74 return true;
75}
76
Marco Nelissen9e503852012-03-16 07:56:42 -070077// static
78sp<XINGSeeker> XINGSeeker::CreateFromSource(
79 const sp<DataSource> &source, off64_t first_frame_pos) {
80 sp<XINGSeeker> seeker = new XINGSeeker;
81
82 seeker->mFirstFramePos = first_frame_pos;
83
Marco Nelissen9e503852012-03-16 07:56:42 -070084 seeker->mSizeBytes = 0;
85 seeker->mTOCValid = false;
86 seeker->mDurationUs = 0;
Andreas Huber4456da52010-11-09 08:57:45 -080087
88 uint8_t buffer[4];
89 int offset = first_frame_pos;
90 if (source->readAt(offset, &buffer, 4) < 4) { // get header
Marco Nelissen9e503852012-03-16 07:56:42 -070091 return NULL;
Andreas Huber4456da52010-11-09 08:57:45 -080092 }
93 offset += 4;
94
Marco Nelissen9e503852012-03-16 07:56:42 -070095 int header = U32_AT(buffer);;
96 size_t xingframesize = 0;
97 int sampling_rate = 0;
98 int num_channels;
99 int samples_per_frame = 0;
100 if (!GetMPEGAudioFrameSize(header, &xingframesize, &sampling_rate, &num_channels,
101 NULL, &samples_per_frame)) {
102 return NULL;
Andreas Huber4456da52010-11-09 08:57:45 -0800103 }
Marco Nelissen9e503852012-03-16 07:56:42 -0700104 seeker->mFirstFramePos += xingframesize;
105
106 uint8_t version = (buffer[1] >> 3) & 3;
107
Andreas Huber4456da52010-11-09 08:57:45 -0800108 // determine offset of XING header
Marco Nelissen9e503852012-03-16 07:56:42 -0700109 if(version & 1) { // mpeg1
110 if (num_channels != 1) offset += 32;
Andreas Huber4456da52010-11-09 08:57:45 -0800111 else offset += 17;
Marco Nelissen9e503852012-03-16 07:56:42 -0700112 } else { // mpeg 2 or 2.5
113 if (num_channels != 1) offset += 17;
Andreas Huber4456da52010-11-09 08:57:45 -0800114 else offset += 9;
115 }
116
Marco Nelissenb636abd2012-03-19 13:49:43 -0700117 int xingbase = offset;
118
Andreas Huber4456da52010-11-09 08:57:45 -0800119 if (source->readAt(offset, &buffer, 4) < 4) { // XING header ID
Marco Nelissen9e503852012-03-16 07:56:42 -0700120 return NULL;
Andreas Huber4456da52010-11-09 08:57:45 -0800121 }
122 offset += 4;
123 // Check XING ID
124 if ((buffer[0] != 'X') || (buffer[1] != 'i')
125 || (buffer[2] != 'n') || (buffer[3] != 'g')) {
126 if ((buffer[0] != 'I') || (buffer[1] != 'n')
127 || (buffer[2] != 'f') || (buffer[3] != 'o')) {
Marco Nelissen9e503852012-03-16 07:56:42 -0700128 return NULL;
Andreas Huber4456da52010-11-09 08:57:45 -0800129 }
130 }
131
132 if (source->readAt(offset, &buffer, 4) < 4) { // flags
Marco Nelissen9e503852012-03-16 07:56:42 -0700133 return NULL;
Andreas Huber4456da52010-11-09 08:57:45 -0800134 }
135 offset += 4;
136 uint32_t flags = U32_AT(buffer);
137
138 if (flags & 0x0001) { // Frames field is present
139 if (source->readAt(offset, buffer, 4) < 4) {
Marco Nelissen9e503852012-03-16 07:56:42 -0700140 return NULL;
Andreas Huber4456da52010-11-09 08:57:45 -0800141 }
Marco Nelissen9e503852012-03-16 07:56:42 -0700142 int32_t frames = U32_AT(buffer);
143 seeker->mDurationUs = (int64_t)frames * samples_per_frame * 1000000LL / sampling_rate;
Andreas Huber4456da52010-11-09 08:57:45 -0800144 offset += 4;
145 }
146 if (flags & 0x0002) { // Bytes field is present
Marco Nelissen9e503852012-03-16 07:56:42 -0700147 if (source->readAt(offset, buffer, 4) < 4) {
148 return NULL;
Andreas Huber4456da52010-11-09 08:57:45 -0800149 }
Marco Nelissen9e503852012-03-16 07:56:42 -0700150 seeker->mSizeBytes = U32_AT(buffer);
Andreas Huber4456da52010-11-09 08:57:45 -0800151 offset += 4;
152 }
153 if (flags & 0x0004) { // TOC field is present
Marco Nelissen9e503852012-03-16 07:56:42 -0700154 if (source->readAt(offset + 1, seeker->mTOC, 99) < 99) {
155 return NULL;
Andreas Huber4456da52010-11-09 08:57:45 -0800156 }
Marco Nelissen9e503852012-03-16 07:56:42 -0700157 seeker->mTOCValid = true;
Andreas Huber4456da52010-11-09 08:57:45 -0800158 offset += 100;
159 }
Marco Nelissen9e503852012-03-16 07:56:42 -0700160
161#if 0
Andreas Huber4456da52010-11-09 08:57:45 -0800162 if (flags & 0x0008) { // Quality indicator field is present
Marco Nelissen9e503852012-03-16 07:56:42 -0700163 if (source->readAt(offset, buffer, 4) < 4) {
164 return NULL;
Andreas Huber4456da52010-11-09 08:57:45 -0800165 }
Marco Nelissen9e503852012-03-16 07:56:42 -0700166 // do something with the quality indicator
167 offset += 4;
Andreas Huber4456da52010-11-09 08:57:45 -0800168 }
Marco Nelissenb636abd2012-03-19 13:49:43 -0700169
170 if (source->readAt(xingbase + 0xaf - 0x24, &buffer, 1) < 1) { // encoding flags
171 return false;
172 }
173
174 ALOGV("nogap preceding: %s, nogap continued in next: %s",
175 (buffer[0] & 0x80) ? "true" : "false",
176 (buffer[0] & 0x40) ? "true" : "false");
Marco Nelissen9e503852012-03-16 07:56:42 -0700177#endif
178
Marco Nelissenb636abd2012-03-19 13:49:43 -0700179 if (source->readAt(xingbase + 0xb1 - 0x24, &buffer, 3) == 3) {
180 seeker->mEncoderDelay = (buffer[0] << 4) + (buffer[1] >> 4);
181 seeker->mEncoderPadding = ((buffer[1] & 0xf) << 8) + buffer[2];
182 }
183
Marco Nelissen9e503852012-03-16 07:56:42 -0700184 return seeker;
Andreas Huber4456da52010-11-09 08:57:45 -0800185}
186
Marco Nelissenb636abd2012-03-19 13:49:43 -0700187int32_t XINGSeeker::getEncoderDelay() {
188 return mEncoderDelay;
189}
190
191int32_t XINGSeeker::getEncoderPadding() {
192 return mEncoderPadding;
193}
194
Andreas Huber4456da52010-11-09 08:57:45 -0800195} // namespace android
196