blob: 211e732e8bfd9cac014df810e0e54552dd99e3bd [file] [log] [blame]
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#define LOG_TAG "TimedTextSRTSource_test"
#include <utils/Log.h>
#include <gtest/gtest.h>
#include <binder/Parcel.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaErrors.h>
#include <utils/misc.h>
#include <TimedTextSource.h>
#include <TimedTextSRTSource.h>
namespace android {
namespace test {
static const int kSecToUsec = 1000000;
static const int kSecToMsec = 1000;
static const int kMsecToUsec = 1000;
/* SRT format (http://en.wikipedia.org/wiki/SubRip)
* Subtitle number
* Start time --> End time
* Text of subtitle (one or more lines)
* Blank lines
*/
static const char *kSRTString =
"1\n00:00:1,000 --> 00:00:1,500\n1\n\n"
"2\n00:00:2,000 --> 00:00:2,500\n2\n\n"
"3\n00:00:3,000 --> 00:00:3,500\n3\n\n"
"4\n00:00:4,000 --> 00:00:4,500\n4\n\n"
"5\n00:00:5,000 --> 00:00:5,500\n5\n\n"
// edge case : previos end time = next start time
"6\n00:00:5,500 --> 00:00:5,800\n6\n\n"
"7\n00:00:5,800 --> 00:00:6,000\n7\n\n"
"8\n00:00:6,000 --> 00:00:7,000\n8\n\n";
class SRTDataSourceStub : public DataSource {
public:
SRTDataSourceStub(const char *data, size_t size) :
mData(data), mSize(size) {}
virtual ~SRTDataSourceStub() {}
virtual status_t initCheck() const {
return OK;
}
virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
if ((size_t)offset >= mSize) return 0;
ssize_t avail = mSize - offset;
if ((size_t)avail > size) {
avail = size;
}
memcpy(data, mData + offset, avail);
return avail;
}
private:
const char *mData;
size_t mSize;
};
class TimedTextSRTSourceTest : public testing::Test {
protected:
void SetUp() {
sp<DataSource> stub= new SRTDataSourceStub(
kSRTString,
strlen(kSRTString));
mSource = new TimedTextSRTSource(stub);
mSource->start();
}
void CheckStartTimeMs(const Parcel& parcel, int32_t timeMs) {
int32_t intval;
parcel.setDataPosition(8);
parcel.readInt32(&intval);
EXPECT_EQ(timeMs, intval);
}
void CheckDataEquals(const Parcel& parcel, const char* content) {
int32_t intval;
parcel.setDataPosition(16);
parcel.readInt32(&intval);
parcel.setDataPosition(24);
const char* data = (const char*) parcel.readInplace(intval);
int32_t content_len = strlen(content);
EXPECT_EQ(content_len, intval);
EXPECT_TRUE(strncmp(data, content, content_len) == 0);
}
sp<TimedTextSource> mSource;
int64_t startTimeUs;
int64_t endTimeUs;
Parcel parcel;
AString subtitle;
status_t err;
};
TEST_F(TimedTextSRTSourceTest, readAll) {
for (int i = 1; i <= 5; i++) {
err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
EXPECT_EQ(OK, err);
CheckStartTimeMs(parcel, i * kSecToMsec);
subtitle = AStringPrintf("%d\n\n", i);
CheckDataEquals(parcel, subtitle.c_str());
}
// read edge cases
err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
EXPECT_EQ(OK, err);
CheckStartTimeMs(parcel, 5500);
subtitle = AStringPrintf("6\n\n");
CheckDataEquals(parcel, subtitle.c_str());
err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
EXPECT_EQ(OK, err);
CheckStartTimeMs(parcel, 5800);
subtitle = AStringPrintf("7\n\n");
CheckDataEquals(parcel, subtitle.c_str());
err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
EXPECT_EQ(OK, err);
CheckStartTimeMs(parcel, 6000);
subtitle = AStringPrintf("8\n\n");
CheckDataEquals(parcel, subtitle.c_str());
err = mSource->read(&startTimeUs, &endTimeUs, &parcel);
EXPECT_EQ(ERROR_END_OF_STREAM, err);
}
TEST_F(TimedTextSRTSourceTest, seekTimeIsEarlierThanFirst) {
MediaSource::ReadOptions options;
options.setSeekTo(500, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(OK, err);
EXPECT_EQ(1 * kSecToUsec, startTimeUs);
CheckStartTimeMs(parcel, 1 * kSecToMsec);
}
TEST_F(TimedTextSRTSourceTest, seekTimeIsLaterThanLast) {
MediaSource::ReadOptions options;
options.setSeekTo(7 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(ERROR_END_OF_STREAM, err);
options.setSeekTo(8 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(ERROR_END_OF_STREAM, err);
}
TEST_F(TimedTextSRTSourceTest, seekTimeIsMatched) {
for (int i = 1; i <= 5; i++) {
MediaSource::ReadOptions options;
options.setSeekTo(i * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(OK, err);
EXPECT_EQ(i * kSecToUsec, startTimeUs);
options.setSeekTo(i * kSecToUsec + 100, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(OK, err);
EXPECT_EQ(i * kSecToUsec, startTimeUs);
}
}
TEST_F(TimedTextSRTSourceTest, seekTimeInBetweenTwo) {
for (int i = 1; i <= 4; i++) {
MediaSource::ReadOptions options;
options.setSeekTo(i * kSecToUsec + 500000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(OK, err);
EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs);
options.setSeekTo(i * kSecToUsec + 600000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(OK, err);
EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs);
}
}
TEST_F(TimedTextSRTSourceTest, checkEdgeCase) {
MediaSource::ReadOptions options;
options.setSeekTo(5500 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(OK, err);
EXPECT_EQ(5500 * kMsecToUsec, startTimeUs);
subtitle = AStringPrintf("6\n\n");
CheckDataEquals(parcel, subtitle.c_str());
options.setSeekTo(5800 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(OK, err);
EXPECT_EQ(5800 * kMsecToUsec, startTimeUs);
subtitle = AStringPrintf("7\n\n");
CheckDataEquals(parcel, subtitle.c_str());
options.setSeekTo(6000 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options);
EXPECT_EQ(OK, err);
EXPECT_EQ(6000 * kMsecToUsec, startTimeUs);
subtitle = AStringPrintf("8\n\n");
CheckDataEquals(parcel, subtitle.c_str());
}
} // namespace test
} // namespace android