Java tutorial
/* * Copyright (C) 2016 Netflix, Inc. * * This file is part of IMF Conversion Utility. * * IMF Conversion Utility is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * IMF Conversion Utility is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with IMF Conversion Utility. If not, see <http://www.gnu.org/licenses/>. */ package com.netflix.imfutility.ttmltostl.stl; import com.netflix.imfutility.ttmltostl.ttml.Style; import com.netflix.imfutility.ttmltostl.ttml.TimedTextObject; import com.netflix.imfutility.ttmltostl.util.StlTestUtil; import org.apache.commons.lang3.StringUtils; import org.junit.Test; import java.util.Arrays; import static junit.framework.TestCase.assertEquals; import static org.junit.Assert.assertArrayEquals; /** * Tests building of STL TTI blocks. */ public class StlTtiTest { @Test public void testSubtitleZero() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:05:00", "text1", "10:00:05:00", "10:00:10:12", "text2", "10:04:59:00", "23:59:59:24", "text3"); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; // subtitle zero assertArrayEquals(new byte[] { 0x00, // group number - 0 0x00, 0x00, // subtitle number - 0 (byte) 0xff, // extension block - default 0x00, // cumulative status - 00 (no cumulative) 0x00, 0x00, 0x00, 0x00, // code in: 00:00:00:00 0x00, 0x00, 0x01, 0x00, // code out: 00:00:01:00 // default for zero subtitle 0x16, // vertical position 0x02, // centered by default 0x00, // comment - 00 (contains subtitle) }, Arrays.copyOfRange(tti, 0, 16)); // 1st block: text assertArrayEquals(fillExpectedText(new byte[] { 0x50, 0x72, 0x6f, 0x67, 0x72, 0x61, 0x6d, 0x6d, 0x65 // 'Programme' as in metadata.xml }), Arrays.copyOfRange(tti, 16, 128)); } @Test public void testSimpleTti() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:05:00", "text1", "10:00:05:00", "10:00:10:12", "text2", "10:04:59:00", "23:59:59:24", "text3"); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; // 1st block: information int offset = 128; // subtitle zero assertArrayEquals(new byte[] { 0x00, // group number - 0 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - default 0x00, // cumulative status - 00 (no cumulative) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x05, 0x00, // code out: 10:00:05:00 0x16, // vertical position 0x02, // centered by default 0x00, // comment - 00 (contains subtitle) }, Arrays.copyOfRange(tti, offset, offset + 16)); // 1st block: text assertArrayEquals(fillExpectedText(new byte[] { 0x74, 0x65, 0x78, 0x74, 0x31 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); // 2d block: information offset += 128; assertArrayEquals(new byte[] { 0x00, // group number - 0 0x02, 0x00, // subtitle number - 2 (byte) 0xff, // extension block - default 0x00, // cumulative status - 00 (no cumulative) 0x0a, 0x00, 0x05, 0x00, // code in: 10:00:05:00 0x0a, 0x00, 0x0a, 0x0c, // code out: 10:00:10:12 0x16, // vertical position 0x02, // centered by default 0x00, // comment - 00 (contains subtitle) }, Arrays.copyOfRange(tti, offset, offset + 16)); // 2d block: text assertArrayEquals(fillExpectedText(new byte[] { 0x74, 0x65, 0x78, 0x74, 0x32 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); // 3d block: information offset += 128; assertArrayEquals(new byte[] { 0x00, // group number - 0 0x03, 0x00, // subtitle number - 3 (byte) 0xff, // extension block - default 0x00, // cumulative status - 00 (no cumulative) 0x0a, 0x04, 0x3b, 0x00, // code in: 10:04:59:00 0x17, 0x3b, 0x3b, 0x18, // code out: 23:59:59:24 0x16, // vertical position 0x02, // centered by default 0x00, // comment - 00 (contains subtitle) }, Arrays.copyOfRange(tti, offset, offset + 16)); // 3d block: text assertArrayEquals(fillExpectedText(new byte[] { 0x74, 0x65, 0x78, 0x74, 0x33 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); } @Test public void testEbnBlocksForLongSubtitle() throws Exception { // prepare long subtitles, so that one subtitles is stored in two tti blocks TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:05:00", StringUtils.rightPad("", 200, '1'), // in 2 tti "10:00:10:00", "10:01:10:00", StringUtils.rightPad("", 400, '2') // in 4 tti ); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; // 1st subtitle 1st block int offset = 128; // zero subtitle; assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0x00, // extension block - 1st 0x00, // cumulative status - 00 (no cumulative) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x05, 0x00, // code out: 10:00:05:00 0x16 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); // 1st subtitle 2d block offset += 128; assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - last 0x00, // cumulative status - 00 (no cumulative) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x05, 0x00, // code out: 10:00:05:00 0x16 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); // 2d subtitle 1st block offset += 128; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0x00, // extension block - 1st 0x00, // cumulative status - 00 (no cumulative) 0x0a, 0x00, 0x0a, 0x00, // code in: 10:00:10:00 0x0a, 0x01, 0x0a, 0x00, // code out: 10:01:10:00 0x16 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); // 2d subtitle 2d block offset += 128; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0x01, // extension block - 2d 0x00, // cumulative status - 00 (no cumulative) 0x0a, 0x00, 0x0a, 0x00, // code in: 10:00:10:00 0x0a, 0x01, 0x0a, 0x00, // code out: 10:01:10:00 0x16 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); // 2d subtitle 3d block offset += 128; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0x02, // extension block - 3d 0x00, // cumulative status - 00 (no cumulative) 0x0a, 0x00, 0x0a, 0x00, // code in: 10:00:10:00 0x0a, 0x01, 0x0a, 0x00, // code out: 10:01:10:00 0x16 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); // 2d subtitle 4th block offset += 128; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0xff, // extension block - last 0x00, // cumulative status - 00 (no cumulative) 0x0a, 0x00, 0x0a, 0x00, // code in: 10:00:10:00 0x0a, 0x01, 0x0a, 0x00, // code out: 10:01:10:00 0x16 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); } /** * Each text must end with 0x8f! * * @throws Exception */ @Test public void testTextEndsWith8H() throws Exception { // prepare long subtitles, so that one subtitles is stored in two tti blocks TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:05:00", StringUtils.rightPad("", 111, '1'), // 1 block "10:00:05:00", "10:00:10:00", StringUtils.rightPad("", 112, '2'), // 2 blocks "10:00:10:00", "10:00:15:00", StringUtils.rightPad("", 222, '3'), // 2 blocks "10:00:15:00", "10:00:20:00", StringUtils.rightPad("", 223, '4') // 3 blocks ); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; // 1st subtitle - 1 block int offset = 128; // subtitle zero byte[] textWithPadding = new byte[112]; Arrays.fill(textWithPadding, (byte) 0x31); textWithPadding[111] = (byte) 0x8f; assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - last }, Arrays.copyOfRange(tti, offset + 1, offset + 4)); assertArrayEquals(textWithPadding, Arrays.copyOfRange(tti, offset + 16, offset + 128)); // 2d subtitle - 2 blocks offset += 128; textWithPadding = new byte[112]; Arrays.fill(textWithPadding, (byte) 0x32); textWithPadding[111] = (byte) 0x8f; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0x00, // extension block - 1st }, Arrays.copyOfRange(tti, offset + 1, offset + 4)); assertArrayEquals(textWithPadding, Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; textWithPadding = new byte[112]; Arrays.fill(textWithPadding, (byte) 0x8f); textWithPadding[0] = (byte) 0x32; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0xff, // extension block - last }, Arrays.copyOfRange(tti, offset + 1, offset + 4)); assertArrayEquals(textWithPadding, Arrays.copyOfRange(tti, offset + 16, offset + 128)); // 3d subtitle - 2 blocks offset += 128; textWithPadding = new byte[112]; Arrays.fill(textWithPadding, (byte) 0x33); textWithPadding[111] = (byte) 0x8f; assertArrayEquals(new byte[] { 0x03, 0x00, // subtitle number - 3 (byte) 0x00, // extension block - 1st }, Arrays.copyOfRange(tti, offset + 1, offset + 4)); assertArrayEquals(textWithPadding, Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertArrayEquals(new byte[] { 0x03, 0x00, // subtitle number - 3 (byte) 0xff, // extension block - last }, Arrays.copyOfRange(tti, offset + 1, offset + 4)); assertArrayEquals(textWithPadding, Arrays.copyOfRange(tti, offset + 16, offset + 128)); // 4th subtitle - 3 blocks offset += 128; textWithPadding = new byte[112]; Arrays.fill(textWithPadding, (byte) 0x34); textWithPadding[111] = (byte) 0x8f; assertArrayEquals(new byte[] { 0x04, 0x00, // subtitle number - 4 (byte) 0x00, // extension block - 1st }, Arrays.copyOfRange(tti, offset + 1, offset + 4)); assertArrayEquals(textWithPadding, Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertArrayEquals(new byte[] { 0x04, 0x00, // subtitle number - 4 (byte) 0x01, // extension block - last }, Arrays.copyOfRange(tti, offset + 1, offset + 4)); assertArrayEquals(textWithPadding, Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; textWithPadding = new byte[112]; Arrays.fill(textWithPadding, (byte) 0x8f); textWithPadding[0] = (byte) 0x34; assertArrayEquals(new byte[] { 0x04, 0x00, // subtitle number - 4 (byte) 0xff, // extension block - last }, Arrays.copyOfRange(tti, offset + 1, offset + 4)); assertArrayEquals(textWithPadding, Arrays.copyOfRange(tti, offset + 16, offset + 128)); } /** * Each line ends with 0x8a. * Vertical position is calculated correctly. * * @throws Exception */ @Test public void testMultilineText() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:05:00", "line1\n2\n3\n\n\n4"); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; int offset = 128; // subtitle zero assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - default 0x00, // cumulative status - 00 (no) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x05, 0x00, // code out: 10:00:05:00 0x0c // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); assertArrayEquals( fillExpectedText(new byte[] { 0x6c, 0x69, 0x6e, 0x65, 0x31, (byte) 0x8a, 0x32, (byte) 0x8a, 0x33, (byte) 0x8a, (byte) 0x8a, (byte) 0x8a, 0x34 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); } /** * It doesn't fail. Sets vertical position to 0. * * @throws Exception */ @Test public void testMultilineTextWithMoreThanMNR() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:05:00", "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14" // 14 > 11 ); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; int offset = 128; // subtitle zero assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - default 0x00, // cumulative status - 00 (no) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x05, 0x00, // code out: 10:00:05:00 0x02 // vertical position (min value!) }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); assertArrayEquals( fillExpectedText(new byte[] { 0x31, (byte) 0x8a, 0x32, (byte) 0x8a, 0x33, (byte) 0x8a, 0x34, (byte) 0x8a, 0x35, (byte) 0x8a, 0x36, (byte) 0x8a, 0x37, (byte) 0x8a, 0x38, (byte) 0x8a, 0x39, (byte) 0x8a, 0x31, 0x30, (byte) 0x8a, 0x31, 0x31, (byte) 0x8a, 0x31, 0x32, (byte) 0x8a, 0x31, 0x33, (byte) 0x8a, 0x31, 0x34 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); } /** * Two subtitles with the same interval are assumed to be cumulative. * * @throws Exception */ @Test public void testCumulativeSubtitleSameTime() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:05:00", "text1", "10:00:00:00", "10:00:05:00", "text2"); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; int offset = 128; // subtitle zero assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - default 0x01, // cumulative status - 01 (first) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x05, 0x00, // code out: 10:00:05:00 0x14 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0xff, // extension block - default 0x03, // cumulative status - 03 (last) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x05, 0x00, // code out: 10:00:05:00 0x16 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); } /** * Classical case of cumulative subtitles (equal end time). * * @throws Exception */ @Test public void testCumulativeSubtitleEqualEndTime() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:10:00", "10:00:20:00", "text3", "10:00:14:00", "10:00:20:00", "text4", "10:00:18:00", "10:00:20:00", "text4"); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; int offset = 128; // subtitle zero assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - default 0x01, // cumulative status - 01 (first) 0x0a, 0x00, 0x0a, 0x00, // code in: 10:00:10:00 0x0a, 0x00, 0x14, 0x00, // code out: 10:00:20:00 0x12 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0xff, // extension block - default 0x02, // cumulative status - 02 (intermediate) 0x0a, 0x00, 0x0e, 0x00, // code in: 10:00:14:00 0x0a, 0x00, 0x14, 0x00, // code out: 10:00:20:00 0x14 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x03, 0x00, // subtitle number - 3 (byte) 0xff, // extension block - default 0x03, // cumulative status - 03 (last) 0x0a, 0x00, 0x12, 0x00, // code in: 10:00:18:00 0x0a, 0x00, 0x14, 0x00, // code out: 10:00:20:00 0x16 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); } /** * When two subtitles are intersected, then the first subtitle is made longer to match cumulative case. * * @throws Exception */ @Test public void testTwoIntersectedSubtitlesMadeCumulative() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:10:00", "text1", "10:00:05:00", "10:00:15:00", "text2"); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; int offset = 128; // subtitle zero assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - default 0x01, // cumulative status - 01 (first) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x0f, 0x00, // code out: 10:00:15:00, not 10:00:10:00!!! 0x14 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0xff, // extension block - default 0x03, // cumulative status - 03 (last) 0x0a, 0x00, 0x05, 0x00, // code in: 10:00:05:00 0x0a, 0x00, 0x0f, 0x00, // code out: 10:00:15:00 0x16 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); } /** * All subtitles are made cumulative and are shown until the last in the cumulative set. * * @throws Exception */ @Test public void testManyIntersectedSubtitlesMadeCumulative() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:10:00", "text1", "10:00:05:00", "10:00:15:00", "text2", "10:00:07:00", "10:00:20:00", "text3", "10:00:08:00", "10:00:20:00", "text4", "10:00:09:00", "10:00:22:00", "text5"); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; int offset = 128; // subtitle zero assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - default 0x01, // cumulative status - 01 (first) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x16, 0x00, // code out: 10:00:22:00, not 10:00:10:00!!! 0x0e // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0xff, // extension block - default 0x02, // cumulative status - 02 (intermediate) 0x0a, 0x00, 0x05, 0x00, // code in: 10:00:05:00 0x0a, 0x00, 0x16, 0x00, // code out: 10:00:22:00 not 10:00:15:00!!! 0x10 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x03, 0x00, // subtitle number - 3 (byte) 0xff, // extension block - default 0x02, // cumulative status - 02 (intermediate) 0x0a, 0x00, 0x07, 0x00, // code in: 10:00:07:00 0x0a, 0x00, 0x16, 0x00, // code out: 10:00:22:00 not 10:00:20:00!!! 0x12 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x04, 0x00, // subtitle number - 4 (byte) 0xff, // extension block - default 0x02, // cumulative status - 02 (intermediate) 0x0a, 0x00, 0x08, 0x00, // code in: 10:00:08:00 0x0a, 0x00, 0x16, 0x00, // code out: 10:00:22:00 not 10:00:20:00!!! 0x14 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x05, 0x00, // subtitle number - 5 (byte) 0xff, // extension block - default 0x03, // cumulative status - 03 (last) 0x0a, 0x00, 0x09, 0x00, // code in: 10:00:09:00 0x0a, 0x00, 0x16, 0x00, // code out: 10:00:22:00 0x16 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); } /** * When maximum number of lines (MNR parameter) is reached, then subtitles from the same cumulative set * are separated to two cumulative sets. * * @throws Exception */ @Test public void testMultilineIntersectedSubtitlesCheckedAgainstMNR() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:10:00", "1\n2\n3\n4\n5", "10:00:05:00", "10:00:15:00", "6\n7\n8\n9\n10\n11", "10:00:07:00", "10:00:22:00", "14\n15", "10:00:08:00", "10:00:22:00", "16\n17"); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; int offset = 128; // subtitle zero assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - default 0x01, // cumulative status - 01 (first) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x0f, 0x00, // code out: 10:00:15:00, not 10:00:10:00!!! 0x02 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0xff, // extension block - default 0x03, // cumulative status - 03 (last) 0x0a, 0x00, 0x05, 0x00, // code in: 10:00:05:00 0x0a, 0x00, 0x0f, 0x00, // code out: 10:00:15:00 0x0c // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x03, 0x00, // subtitle number - 3 (byte) 0xff, // extension block - default 0x01, // cumulative status - 01 (first) 0x0a, 0x00, 0x0f, 0x00, // code in: 10:00:15:00, not 10:00:07:00!!! 0x0a, 0x00, 0x16, 0x00, // code out: 10:00:22:00 0x10 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x04, 0x00, // subtitle number - 4 (byte) 0xff, // extension block - default 0x03, // cumulative status - 02 (last) 0x0a, 0x00, 0x0f, 0x00, // code in: 10:00:15:00, not 10:00:08:00!!! 0x0a, 0x00, 0x16, 0x00, // code out: 10:00:22:00 0x14 // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); } /** * Tests correct separation of cumulative set if frist subtitle has more than MNR (11) lines. * * @throws Exception */ @Test public void testMultilineCumulativeFirstMoreThanMNR() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:10:00", "1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13", "10:00:05:00", "10:00:15:00", "6\n7\n8\n9\n10\n11"); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; int offset = 128; // subtitle zero assertArrayEquals(new byte[] { 0x01, 0x00, // subtitle number - 1 (byte) 0xff, // extension block - default 0x00, // cumulative status - 00 (no) 0x0a, 0x00, 0x00, 0x00, // code in: 10:00:00:00 0x0a, 0x00, 0x0a, 0x00, // code out: 10:00:10:00, not 10:00:15:00!!! 0x02 // vertical position (min) }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); offset += 128; assertArrayEquals(new byte[] { 0x02, 0x00, // subtitle number - 2 (byte) 0xff, // extension block - default 0x00, // cumulative status - 00 (no) 0x0a, 0x00, 0x0a, 0x00, // code in: 10:00:10:00, not 10:00:05:00!!! 0x0a, 0x00, 0x0f, 0x00, // code out: 10:00:15:00 0x0c // vertical position }, Arrays.copyOfRange(tti, offset + 1, offset + 14)); } /** * Checks that text is aligned correctly * * @throws Exception */ @Test public void testTextAlign() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:05:00", "text1", "10:00:05:00", "10:00:10:12", "text2", "10:04:59:00", "23:59:59:24", "text3"); // set styles Style style1 = new Style("1"); style1.setTextAlign("top-left"); Style style2 = new Style("2"); style2.setTextAlign("bottom-right"); Style style3 = new Style("3"); style3.setTextAlign("center"); tto.getCaptions().get(0).setStyle(style1); tto.getCaptions().get(1).setStyle(style2); tto.getCaptions().get(2).setStyle(style3); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; int offset = 128; // subtitle zero assertEquals(0x01, tti[offset + 14]); // 01 - left assertArrayEquals(fillExpectedText(new byte[] { 0x74, 0x65, 0x78, 0x74, 0x31 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertEquals(0x03, tti[offset + 14]); // 03 - right assertArrayEquals(fillExpectedText(new byte[] { 0x74, 0x65, 0x78, 0x74, 0x32 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertEquals(0x02, tti[offset + 14]); // 02 - center assertArrayEquals(fillExpectedText(new byte[] { 0x74, 0x65, 0x78, 0x74, 0x33 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); } @Test public void testTextColor() throws Exception { TimedTextObject tto = StlTestUtil.buildTto("10:00:00:00", "10:00:05:00", "text1", "10:00:05:00", "10:00:10:12", "text2", "10:00:15:00", "10:00:20:24", "text3", "10:00:20:00", "10:00:25:24", "text4", "10:00:25:00", "10:00:30:24", "text5", "10:00:30:00", "10:00:35:24", "text6", "10:00:35:00", "10:00:40:24", "text7", "10:00:40:00", "10:00:45:24", "text8", "10:00:45:00", "10:00:50:24", "text9"); // set styles Style style1 = new Style("1"); style1.setColor("000000ff"); // black Style style2 = new Style("2"); style2.setColor("FF0000ff"); // red Style style3 = new Style("3"); style3.setColor("00ff00"); // green Style style4 = new Style("4"); style4.setColor("FFff00"); // yellow Style style5 = new Style("5"); style5.setColor("0000ff"); // blue Style style6 = new Style("6"); style6.setColor("ff00ffff"); // magenta Style style7 = new Style("7"); style7.setColor("00ffffFF"); // cyn Style style8 = new Style("8"); style8.setColor("ffffffff"); // white Style style9 = new Style("9"); style9.setColor("0f0f0fff"); // some color (fallback to white) tto.getCaptions().get(0).setStyle(style1); tto.getCaptions().get(1).setStyle(style2); tto.getCaptions().get(2).setStyle(style3); tto.getCaptions().get(3).setStyle(style4); tto.getCaptions().get(4).setStyle(style5); tto.getCaptions().get(5).setStyle(style6); tto.getCaptions().get(6).setStyle(style7); tto.getCaptions().get(7).setStyle(style8); tto.getCaptions().get(8).setStyle(style9); byte[][] stl = StlTestUtil.build(tto, StlTestUtil.getMetadataXml()); byte[] tti = stl[1]; int offset = 128; // subtitle zero assertArrayEquals(fillExpectedText(new byte[] { 0x00, // black 0x74, 0x65, 0x78, 0x74, 0x31 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertArrayEquals(fillExpectedText(new byte[] { 0x01, // red 0x74, 0x65, 0x78, 0x74, 0x32 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertArrayEquals(fillExpectedText(new byte[] { 0x02, // green 0x74, 0x65, 0x78, 0x74, 0x33 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertArrayEquals(fillExpectedText(new byte[] { 0x03, // yellow 0x74, 0x65, 0x78, 0x74, 0x34 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertArrayEquals(fillExpectedText(new byte[] { 0x04, // blue 0x74, 0x65, 0x78, 0x74, 0x35 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertArrayEquals(fillExpectedText(new byte[] { 0x05, // magenta 0x74, 0x65, 0x78, 0x74, 0x36 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertArrayEquals(fillExpectedText(new byte[] { 0x06, // cyn 0x74, 0x65, 0x78, 0x74, 0x37 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertArrayEquals(fillExpectedText(new byte[] { 0x07, // white 0x74, 0x65, 0x78, 0x74, 0x38 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); offset += 128; assertArrayEquals(fillExpectedText(new byte[] { 0x07, // fallback - white 0x74, 0x65, 0x78, 0x74, 0x39 }), Arrays.copyOfRange(tti, offset + 16, offset + 128)); } private byte[] fillExpectedText(byte[] text) { byte[] textWithPadding = new byte[112]; Arrays.fill(textWithPadding, (byte) 0x8f); System.arraycopy(text, 0, textWithPadding, 0, text.length); return textWithPadding; } }