Example #1
0
status_t MP3Source::getNextFramePos(off_t *curPos, off_t *pNextPos,int64_t * frameTsUs)
{
	
	uint8_t mp3header[4];
	size_t frame_size;
	int samplerate=0;
	int num_sample =0;
	for(;;)
	{
		ssize_t n = mDataSource->readAt(*curPos, mp3header, 4);
		if (n < 4) {
			MP3_EXTR_DBG("For Seek Talbe :ERROR_END_OF_STREAM");
			return ERROR_END_OF_STREAM;
		}
       // MP3_EXTR_DBG("mp3header[0]=%0x,mp3header[1]=%0x,mp3header[2]=%0x,mp3header[3]=%0x",mp3header[0],mp3header[1],mp3header[2],mp3header[3]); 
        uint32_t header = U32_AT((const uint8_t *)mp3header);      
        if ((header & kMask) == (mFixedHeader & kMask)
            && GetMPEGAudioFrameSize(header, &frame_size,
								&samplerate, NULL,NULL,&num_sample)) 
		{            	  
            break; 
        }
        // Lost sync.
        //MP3_EXTR_DBG("getNextFramePos::lost sync! header = 0x%08x, old header = 0x%08x\n", header, mFixedHeader);
        off64_t pos = *curPos;
        if (!Resync(mDataSource, mFixedHeader, &pos, NULL,NULL)) {
             //MP3_EXTR_DBG("getNextFramePos---Unable to resync. Signalling end of stream.");          
             return ERROR_END_OF_STREAM;
        }
        *curPos = pos;       
        // Try again with the new position.
     }
     *pNextPos=*curPos+frame_size;
	 *frameTsUs = 1000000ll * num_sample/samplerate;
   return OK;
}
Example #2
0
status_t MP3Source::read(
        MediaBuffer **out, const ReadOptions *options) {
    *out = NULL;

    int64_t seekTimeUs;
    ReadOptions::SeekMode mode;
    bool seekCBR = false;

    if (options != NULL && options->getSeekTo(&seekTimeUs, &mode)) {
        int64_t actualSeekTimeUs = seekTimeUs;
#ifndef ANDROID_DEFAULT_CODE
		if(!mEnableTOC){
#endif
        if (mSeeker == NULL
                || !mSeeker->getOffsetForTime(&actualSeekTimeUs, &mCurrentPos)) {
            int32_t bitrate;
            if (!mMeta->findInt32(kKeyBitRate, &bitrate)) {
                // bitrate is in bits/sec.
                ALOGI("no bitrate");

                return ERROR_UNSUPPORTED;
            }

            mCurrentTimeUs = seekTimeUs;
            mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 8000000;
            seekCBR = true;
        } else {
            mCurrentTimeUs = actualSeekTimeUs;
        }
#ifndef ANDROID_DEFAULT_CODE
		}else{
			MP3_EXTR_DBG("before getFramePos seekTimeUs=%lld",seekTimeUs);
			off_t ActualPos=0;
			status_t stat=getFramePos(seekTimeUs, &mCurrentTimeUs, &ActualPos, true);		 
			if(stat==BAD_VALUE){
				int32_t bitrate;
	            if (!mMeta->findInt32(kKeyBitRate, &bitrate)) {
	                // bitrate is in bits/sec.
	                MP3_EXTR_WARN("no bitrate");
	                return ERROR_UNSUPPORTED;
	            }
				mCurrentTimeUs = seekTimeUs;
				mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 8000000;
				if (mSeeker == NULL || !mSeeker->getOffsetForTime(&actualSeekTimeUs, &mCurrentPos)) {
            		int32_t bitrate;
            		if (!mMeta->findInt32(kKeyBitRate, &bitrate)) {
              		  // bitrate is in bits/sec.
                		ALOGI("no bitrate");

             		   return ERROR_UNSUPPORTED;
           			 }

            		mCurrentTimeUs = seekTimeUs;
            		mCurrentPos = mFirstFramePos + seekTimeUs * bitrate / 8000000;
            		seekCBR = true;
        		} else {
            		mCurrentTimeUs = actualSeekTimeUs;
       			}
			}else if(stat == ERROR_END_OF_STREAM){
				return stat;
			}else{
				mCurrentPos= ActualPos;
				MP3_EXTR_DBG("after seek mCurrentTimeUs=%lld,pActualPos=%ld",mCurrentTimeUs,ActualPos);
			}


		}
#endif
        mBasisTimeUs = mCurrentTimeUs;
        mSamplesRead = 0;
    }

    MediaBuffer *buffer;
    status_t err = mGroup->acquire_buffer(&buffer);
    if (err != OK) {
        return err;
    }

    size_t frame_size;
    int bitrate;
    int num_samples;
    int sample_rate;
    for (;;) {
        ssize_t n = mDataSource->readAt(mCurrentPos, buffer->data(), 4);
        if (n < 4) {
            buffer->release();
            buffer = NULL;

            return ERROR_END_OF_STREAM;
        }

        uint32_t header = U32_AT((const uint8_t *)buffer->data());

        if ((header & kMask) == (mFixedHeader & kMask)
            && GetMPEGAudioFrameSize(
                header, &frame_size, &sample_rate, NULL,
                &bitrate, &num_samples)) {

            // re-calculate mCurrentTimeUs because we might have called Resync()
            if (seekCBR) {
                mCurrentTimeUs = (mCurrentPos - mFirstFramePos) * 8000 / bitrate;
                mBasisTimeUs = mCurrentTimeUs;
            }

            break;
        }

        // Lost sync.
        ALOGV("lost sync! header = 0x%08x, old header = 0x%08x\n", header, mFixedHeader);

        off64_t pos = mCurrentPos;
        if (!Resync(mDataSource, mFixedHeader, &pos, NULL, NULL)) {
            ALOGE("Unable to resync. Signalling end of stream.");

            buffer->release();
            buffer = NULL;

            return ERROR_END_OF_STREAM;
        }

        mCurrentPos = pos;

        // Try again with the new position.
    }

    CHECK(frame_size <= buffer->size());

    ssize_t n = mDataSource->readAt(mCurrentPos, buffer->data(), frame_size);
    if (n < (ssize_t)frame_size) {
        buffer->release();
        buffer = NULL;

        return ERROR_END_OF_STREAM;
    }

    buffer->set_range(0, frame_size);

    buffer->meta_data()->setInt64(kKeyTime, mCurrentTimeUs);
    buffer->meta_data()->setInt32(kKeyIsSyncFrame, 1);

    mCurrentPos += frame_size;

    mSamplesRead += num_samples;
    mCurrentTimeUs = mBasisTimeUs + ((mSamplesRead * 1000000) / sample_rate);

    *out = buffer;

    return OK;
}
Example #3
0
bool FastSniffMP3(
    const sp<DataSource> &source, String8 *mimeType,
    float *confidence, sp<AMessage> *meta) {
    off64_t inout_pos = 0;
    off64_t post_id3_pos;
    uint32_t header;

    if (inout_pos == 0) {
        // Skip an optional ID3 header if syncing at the very beginning
        // of the datasource.

        for (;;) {
            uint8_t id3header[10];

            if (source->readAt(inout_pos, id3header, sizeof(id3header))
                    < (ssize_t)sizeof(id3header)) {
                ALOGV("Read no enough data");
                return false;
            }

            if (memcmp("ID3", id3header, 3)) {
                break;
            }

            size_t len =
                ((id3header[6] & 0x7f) << 21)
                | ((id3header[7] & 0x7f) << 14)
                | ((id3header[8] & 0x7f) << 7)
                | (id3header[9] & 0x7f);

            len += 10;

            inout_pos += len;

        }

        post_id3_pos = inout_pos;
    }

    off64_t pos = inout_pos;
    bool valid = true;
    uint32_t test_header = 0;
    
    for (int j = 0; j < 4; ++j) {
        uint8_t tmp[4];

        if (source->readAt(pos, tmp, 4) < 4) {
            valid = false;
            break;
        }

        test_header = U32_AT(tmp);

        size_t test_frame_size;

        if (!GetMPEGAudioFrameSize(
                    test_header, &test_frame_size)) {
            valid = false;
            break;
        }

        ALOGV("found subsequent frame #%d at %lld", j + 2, pos);

        pos += test_frame_size;
    }

    if (false == valid) 
    {
        ALOGV("no dice, no valid sequence of frames found.");
        return false;
    }
    else
        header = test_header;


    *meta = new AMessage;
    (*meta)->setInt64("offset", inout_pos);
    (*meta)->setInt32("header", header);
    (*meta)->setInt64("post-id3-offset", inout_pos);

    *mimeType = MEDIA_MIMETYPE_AUDIO_MPEG;
    *confidence = 0.2f;

    return true;
}
static bool Resync(
        const sp<DataSource> &source, uint32_t match_header,
        off64_t *inout_pos, off64_t *post_id3_pos, uint32_t *out_header) {
    if (post_id3_pos != NULL) {
        *post_id3_pos = 0;
    }

    if (*inout_pos == 0) {
        // Skip an optional ID3 header if syncing at the very beginning
        // of the datasource.

        for (;;) {
            uint8_t id3header[10];
            if (source->readAt(*inout_pos, id3header, sizeof(id3header))
                    < (ssize_t)sizeof(id3header)) {
                // If we can't even read these 10 bytes, we might as well bail
                // out, even if there _were_ 10 bytes of valid mp3 audio data...
                return false;
            }

            if (memcmp("ID3", id3header, 3)) {
                break;
            }

            // Skip the ID3v2 header.

            size_t len =
                ((id3header[6] & 0x7f) << 21)
                | ((id3header[7] & 0x7f) << 14)
                | ((id3header[8] & 0x7f) << 7)
                | (id3header[9] & 0x7f);

            len += 10;

            *inout_pos += len;

            LOGV("skipped ID3 tag, new starting offset is %lld (0x%016llx)",
                 *inout_pos, *inout_pos);
        }

        if (post_id3_pos != NULL) {
            *post_id3_pos = *inout_pos;
        }
    }

    off64_t pos = *inout_pos;
    bool valid = false;

    const size_t kMaxReadBytes = 1024;
    const size_t kMaxBytesChecked = 128 * 1024;
    uint8_t buf[kMaxReadBytes];
    ssize_t bytesToRead = kMaxReadBytes;
    ssize_t totalBytesRead = 0;
    ssize_t remainingBytes = 0;
    bool reachEOS = false;
    uint8_t *tmp = buf;

    do {
        if (pos >= *inout_pos + kMaxBytesChecked) {
            // Don't scan forever.
            LOGV("giving up at offset %lld", pos);
            break;
        }

        if (remainingBytes < 4) {
            if (reachEOS) {
                break;
            } else {
                memcpy(buf, tmp, remainingBytes);
                bytesToRead = kMaxReadBytes - remainingBytes;

                /*
                 * The next read position should start from the end of
                 * the last buffer, and thus should include the remaining
                 * bytes in the buffer.
                 */
                totalBytesRead = source->readAt(pos + remainingBytes,
                                                buf + remainingBytes,
                                                bytesToRead);
                if (totalBytesRead <= 0) {
                    break;
                }
                reachEOS = (totalBytesRead != bytesToRead);
                totalBytesRead += remainingBytes;
                remainingBytes = totalBytesRead;
                tmp = buf;
                continue;
            }
        }

        uint32_t header = U32_AT(tmp);

        if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
            ++pos;
            ++tmp;
            --remainingBytes;
            continue;
        }

        size_t frame_size;
        int sample_rate, num_channels, bitrate;
        if (!GetMPEGAudioFrameSize(
                    header, &frame_size,
                    &sample_rate, &num_channels, &bitrate)) {
            ++pos;
            ++tmp;
            --remainingBytes;
            continue;
        }

        LOGV("found possible 1st frame at %lld (header = 0x%08x)", pos, header);

        // We found what looks like a valid frame,
        // now find its successors.

        off64_t test_pos = pos + frame_size;

        valid = true;
        for (int j = 0; j < 3; ++j) {
            uint8_t tmp[4];
            if (source->readAt(test_pos, tmp, 4) < 4) {
                valid = false;
                break;
            }

            uint32_t test_header = U32_AT(tmp);

            LOGV("subsequent header is %08x", test_header);

            if ((test_header & kMask) != (header & kMask)) {
                valid = false;
                break;
            }

            size_t test_frame_size;
            if (!GetMPEGAudioFrameSize(
                        test_header, &test_frame_size)) {
                valid = false;
                break;
            }

            LOGV("found subsequent frame #%d at %lld", j + 2, test_pos);

            test_pos += test_frame_size;
        }

        if (valid) {
            *inout_pos = pos;

            if (out_header != NULL) {
                *out_header = header;
            }
        } else {
            LOGV("no dice, no valid sequence of frames found.");
        }

        ++pos;
        ++tmp;
        --remainingBytes;
    } while (!valid);

    return valid;
}
MP3Extractor::MP3Extractor(
        const sp<DataSource> &source, const sp<AMessage> &meta)
    : mInitCheck(NO_INIT),
      mDataSource(source),
      mFirstFramePos(-1),
      mFixedHeader(0) {
    off64_t pos = 0;
    off64_t post_id3_pos;
    uint32_t header;
    bool success;

    int64_t meta_offset;
    uint32_t meta_header;
    int64_t meta_post_id3_offset;
    if (meta != NULL
            && meta->findInt64("offset", &meta_offset)
            && meta->findInt32("header", (int32_t *)&meta_header)
            && meta->findInt64("post-id3-offset", &meta_post_id3_offset)) {
        // The sniffer has already done all the hard work for us, simply
        // accept its judgement.
        pos = (off64_t)meta_offset;
        header = meta_header;
        post_id3_pos = (off64_t)meta_post_id3_offset;

        success = true;
    } else {
        success = Resync(mDataSource, 0, &pos, &post_id3_pos, &header);
    }

    if (!success) {
        // mInitCheck will remain NO_INIT
        return;
    }

    mFirstFramePos = pos;
    mFixedHeader = header;

    size_t frame_size;
    int sample_rate;
    int num_channels;
    int bitrate;
    GetMPEGAudioFrameSize(
            header, &frame_size, &sample_rate, &num_channels, &bitrate);

    mMeta = new MetaData;

    mMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MPEG);
    mMeta->setInt32(kKeySampleRate, sample_rate);
    mMeta->setInt32(kKeyBitRate, bitrate * 1000);
    mMeta->setInt32(kKeyChannelCount, num_channels);

    mSeeker = XINGSeeker::CreateFromSource(mDataSource, mFirstFramePos);

    if (mSeeker == NULL) {
        mSeeker = VBRISeeker::CreateFromSource(mDataSource, post_id3_pos);
    }

    int64_t durationUs;

    if (mSeeker == NULL || !mSeeker->getDuration(&durationUs)) {
        off64_t fileSize;
        if (mDataSource->getSize(&fileSize) == OK) {
            durationUs = 8000LL * (fileSize - mFirstFramePos) / bitrate;
        } else {
            durationUs = -1;
        }
    }

    if (durationUs >= 0) {
        mMeta->setInt64(kKeyDuration, durationUs);
    }

    mInitCheck = OK;
}
// static
sp<VBRISeeker> VBRISeeker::CreateFromSource(
        const sp<DataSource> &source, off64_t post_id3_pos) {
    off64_t pos = post_id3_pos;

    uint8_t header[4];
    ssize_t n = source->readAt(pos, header, sizeof(header));
    if (n < (ssize_t)sizeof(header)) {
        return NULL;
    }

    uint32_t tmp = U32_AT(&header[0]);
    size_t frameSize;
    int sampleRate;
    if (!GetMPEGAudioFrameSize(tmp, &frameSize, &sampleRate)) {
        return NULL;
    }

    // VBRI header follows 32 bytes after the header _ends_.
    pos += sizeof(header) + 32;

    uint8_t vbriHeader[26];
    n = source->readAt(pos, vbriHeader, sizeof(vbriHeader));
    if (n < (ssize_t)sizeof(vbriHeader)) {
        return NULL;
    }

    if (memcmp(vbriHeader, "VBRI", 4)) {
        return NULL;
    }

    size_t numFrames = U32_AT(&vbriHeader[14]);

    int64_t durationUs =
        numFrames * 1000000ll * (sampleRate >= 32000 ? 1152 : 576) / sampleRate;

    ALOGV("duration = %.2f secs", durationUs / 1E6);

    size_t numEntries = U16_AT(&vbriHeader[18]);
    size_t entrySize = U16_AT(&vbriHeader[22]);
    size_t scale = U16_AT(&vbriHeader[20]);

    ALOGV("%zu entries, scale=%zu, size_per_entry=%zu",
         numEntries,
         scale,
         entrySize);

    size_t totalEntrySize = numEntries * entrySize;
    uint8_t *buffer = new uint8_t[totalEntrySize];

    n = source->readAt(pos + sizeof(vbriHeader), buffer, totalEntrySize);
    if (n < (ssize_t)totalEntrySize) {
        delete[] buffer;
        buffer = NULL;

        return NULL;
    }

    sp<VBRISeeker> seeker = new VBRISeeker;
    seeker->mBasePos = post_id3_pos + frameSize;
    // only update mDurationUs if the calculated duration is valid (non zero)
    // otherwise, leave duration at -1 so that getDuration() and getOffsetForTime()
    // return false when called, to indicate that this vbri tag does not have the
    // requested information
    if (durationUs) {
        seeker->mDurationUs = durationUs;
    }

    off64_t offset = post_id3_pos;
    for (size_t i = 0; i < numEntries; ++i) {
        uint32_t numBytes;
        switch (entrySize) {
            case 1: numBytes = buffer[i]; break;
            case 2: numBytes = U16_AT(buffer + 2 * i); break;
            case 3: numBytes = U24_AT(buffer + 3 * i); break;
            default:
            {
                CHECK_EQ(entrySize, 4u);
                numBytes = U32_AT(buffer + 4 * i); break;
            }
        }

        numBytes *= scale;

        seeker->mSegments.push(numBytes);

        ALOGV("entry #%zu: %u offset 0x%016llx", i, numBytes, offset);
        offset += numBytes;
    }

    delete[] buffer;
    buffer = NULL;

    ALOGI("Found VBRI header.");

    return seeker;
}