1 /* 2 * Copyright (C) 2012 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 #define LOG_TAG "TimedTextSRTSource_test" 18 #include <utils/Log.h> 19 20 #include <gtest/gtest.h> 21 22 #include <binder/Parcel.h> 23 #include <media/stagefright/foundation/AString.h> 24 #include <media/stagefright/DataSource.h> 25 #include <media/stagefright/MediaErrors.h> 26 #include <utils/misc.h> 27 28 #include <TimedTextSource.h> 29 #include <TimedTextSRTSource.h> 30 31 namespace android { 32 namespace test { 33 34 static const int kSecToUsec = 1000000; 35 static const int kSecToMsec = 1000; 36 static const int kMsecToUsec = 1000; 37 38 /* SRT format (http://en.wikipedia.org/wiki/SubRip) 39 * Subtitle number 40 * Start time --> End time 41 * Text of subtitle (one or more lines) 42 * Blank lines 43 */ 44 static const char *kSRTString = 45 "1\n00:00:1,000 --> 00:00:1,500\n1\n\n" 46 "2\n00:00:2,000 --> 00:00:2,500\n2\n\n" 47 "3\n00:00:3,000 --> 00:00:3,500\n3\n\n" 48 "4\n00:00:4,000 --> 00:00:4,500\n4\n\n" 49 "5\n00:00:5,000 --> 00:00:5,500\n5\n\n" 50 // edge case : previos end time = next start time 51 "6\n00:00:5,500 --> 00:00:5,800\n6\n\n" 52 "7\n00:00:5,800 --> 00:00:6,000\n7\n\n" 53 "8\n00:00:6,000 --> 00:00:7,000\n8\n\n"; 54 55 class SRTDataSourceStub : public DataSource { 56 public: 57 SRTDataSourceStub(const char *data, size_t size) : 58 mData(data), mSize(size) {} 59 virtual ~SRTDataSourceStub() {} 60 61 virtual status_t initCheck() const { 62 return OK; 63 } 64 65 virtual ssize_t readAt(off64_t offset, void *data, size_t size) { 66 if (offset >= mSize) return 0; 67 68 ssize_t avail = mSize - offset; 69 if (avail > size) { 70 avail = size; 71 } 72 memcpy(data, mData + offset, avail); 73 return avail; 74 } 75 76 private: 77 const char *mData; 78 size_t mSize; 79 }; 80 81 class TimedTextSRTSourceTest : public testing::Test { 82 protected: 83 void SetUp() { 84 sp<DataSource> stub= new SRTDataSourceStub( 85 kSRTString, 86 strlen(kSRTString)); 87 mSource = new TimedTextSRTSource(stub); 88 mSource->start(); 89 } 90 91 void CheckStartTimeMs(const Parcel& parcel, int32_t timeMs) { 92 int32_t intval; 93 parcel.setDataPosition(8); 94 parcel.readInt32(&intval); 95 EXPECT_EQ(timeMs, intval); 96 } 97 98 void CheckDataEquals(const Parcel& parcel, const char* content) { 99 int32_t intval; 100 parcel.setDataPosition(16); 101 parcel.readInt32(&intval); 102 parcel.setDataPosition(24); 103 const char* data = (const char*) parcel.readInplace(intval); 104 105 int32_t content_len = strlen(content); 106 EXPECT_EQ(content_len, intval); 107 EXPECT_TRUE(strncmp(data, content, content_len) == 0); 108 } 109 110 sp<TimedTextSource> mSource; 111 int64_t startTimeUs; 112 int64_t endTimeUs; 113 Parcel parcel; 114 AString subtitle; 115 status_t err; 116 }; 117 118 TEST_F(TimedTextSRTSourceTest, readAll) { 119 for (int i = 1; i <= 5; i++) { 120 err = mSource->read(&startTimeUs, &endTimeUs, &parcel); 121 EXPECT_EQ(OK, err); 122 CheckStartTimeMs(parcel, i * kSecToMsec); 123 subtitle = StringPrintf("%d\n\n", i); 124 CheckDataEquals(parcel, subtitle.c_str()); 125 } 126 // read edge cases 127 err = mSource->read(&startTimeUs, &endTimeUs, &parcel); 128 EXPECT_EQ(OK, err); 129 CheckStartTimeMs(parcel, 5500); 130 subtitle = StringPrintf("6\n\n"); 131 CheckDataEquals(parcel, subtitle.c_str()); 132 133 err = mSource->read(&startTimeUs, &endTimeUs, &parcel); 134 EXPECT_EQ(OK, err); 135 CheckStartTimeMs(parcel, 5800); 136 subtitle = StringPrintf("7\n\n"); 137 CheckDataEquals(parcel, subtitle.c_str()); 138 139 err = mSource->read(&startTimeUs, &endTimeUs, &parcel); 140 EXPECT_EQ(OK, err); 141 CheckStartTimeMs(parcel, 6000); 142 subtitle = StringPrintf("8\n\n"); 143 CheckDataEquals(parcel, subtitle.c_str()); 144 145 err = mSource->read(&startTimeUs, &endTimeUs, &parcel); 146 EXPECT_EQ(ERROR_END_OF_STREAM, err); 147 } 148 149 TEST_F(TimedTextSRTSourceTest, seekTimeIsEarlierThanFirst) { 150 MediaSource::ReadOptions options; 151 options.setSeekTo(500, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 152 err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options); 153 EXPECT_EQ(OK, err); 154 EXPECT_EQ(1 * kSecToUsec, startTimeUs); 155 CheckStartTimeMs(parcel, 1 * kSecToMsec); 156 } 157 158 TEST_F(TimedTextSRTSourceTest, seekTimeIsLaterThanLast) { 159 MediaSource::ReadOptions options; 160 options.setSeekTo(7 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 161 err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options); 162 EXPECT_EQ(ERROR_END_OF_STREAM, err); 163 164 options.setSeekTo(8 * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 165 err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options); 166 EXPECT_EQ(ERROR_END_OF_STREAM, err); 167 } 168 169 TEST_F(TimedTextSRTSourceTest, seekTimeIsMatched) { 170 for (int i = 1; i <= 5; i++) { 171 MediaSource::ReadOptions options; 172 options.setSeekTo(i * kSecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 173 err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options); 174 EXPECT_EQ(OK, err); 175 EXPECT_EQ(i * kSecToUsec, startTimeUs); 176 177 options.setSeekTo(i * kSecToUsec + 100, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 178 err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options); 179 EXPECT_EQ(OK, err); 180 EXPECT_EQ(i * kSecToUsec, startTimeUs); 181 } 182 } 183 184 TEST_F(TimedTextSRTSourceTest, seekTimeInBetweenTwo) { 185 for (int i = 1; i <= 4; i++) { 186 MediaSource::ReadOptions options; 187 options.setSeekTo(i * kSecToUsec + 500000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 188 err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options); 189 EXPECT_EQ(OK, err); 190 EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs); 191 192 options.setSeekTo(i * kSecToUsec + 600000, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 193 err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options); 194 EXPECT_EQ(OK, err); 195 EXPECT_EQ((i + 1) * kSecToUsec, startTimeUs); 196 } 197 } 198 199 TEST_F(TimedTextSRTSourceTest, checkEdgeCase) { 200 MediaSource::ReadOptions options; 201 options.setSeekTo(5500 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 202 err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options); 203 EXPECT_EQ(OK, err); 204 EXPECT_EQ(5500 * kMsecToUsec, startTimeUs); 205 subtitle = StringPrintf("6\n\n"); 206 CheckDataEquals(parcel, subtitle.c_str()); 207 208 options.setSeekTo(5800 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 209 err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options); 210 EXPECT_EQ(OK, err); 211 EXPECT_EQ(5800 * kMsecToUsec, startTimeUs); 212 subtitle = StringPrintf("7\n\n"); 213 CheckDataEquals(parcel, subtitle.c_str()); 214 215 options.setSeekTo(6000 * kMsecToUsec, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC); 216 err = mSource->read(&startTimeUs, &endTimeUs, &parcel, &options); 217 EXPECT_EQ(OK, err); 218 EXPECT_EQ(6000 * kMsecToUsec, startTimeUs); 219 subtitle = StringPrintf("8\n\n"); 220 CheckDataEquals(parcel, subtitle.c_str()); 221 } 222 223 } // namespace test 224 } // namespace android 225