| /* |
| * 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 |