1/*
2 * Copyright 2012 Sebastian Annies, Hamburg
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 */
16package com.googlecode.mp4parser.authoring.tracks;
17
18import com.coremedia.iso.boxes.*;
19import com.coremedia.iso.boxes.sampleentry.TextSampleEntry;
20import com.googlecode.mp4parser.authoring.AbstractTrack;
21import com.googlecode.mp4parser.authoring.TrackMetaData;
22import com.googlecode.mp4parser.boxes.apple.BaseMediaInfoAtom;
23import com.googlecode.mp4parser.boxes.apple.GenericMediaHeaderAtom;
24import com.googlecode.mp4parser.boxes.apple.GenericMediaHeaderTextAtom;
25import com.googlecode.mp4parser.boxes.apple.QuicktimeTextSampleEntry;
26import com.googlecode.mp4parser.boxes.threegpp26245.FontTableBox;
27
28import java.io.ByteArrayOutputStream;
29import java.io.DataOutputStream;
30import java.io.IOException;
31import java.nio.ByteBuffer;
32import java.util.Collections;
33import java.util.Date;
34import java.util.LinkedList;
35import java.util.List;
36
37/**
38 * A Text track as Quicktime Pro would create.
39 */
40public class QuicktimeTextTrackImpl extends AbstractTrack {
41    TrackMetaData trackMetaData = new TrackMetaData();
42    SampleDescriptionBox sampleDescriptionBox;
43    List<Line> subs = new LinkedList<Line>();
44
45    public List<Line> getSubs() {
46        return subs;
47    }
48
49    public QuicktimeTextTrackImpl() {
50        sampleDescriptionBox = new SampleDescriptionBox();
51        QuicktimeTextSampleEntry textTrack = new QuicktimeTextSampleEntry();
52        textTrack.setDataReferenceIndex(1);
53        sampleDescriptionBox.addBox(textTrack);
54
55
56        trackMetaData.setCreationTime(new Date());
57        trackMetaData.setModificationTime(new Date());
58        trackMetaData.setTimescale(1000);
59
60
61    }
62
63
64    public List<ByteBuffer> getSamples() {
65        List<ByteBuffer> samples = new LinkedList<ByteBuffer>();
66        long lastEnd = 0;
67        for (Line sub : subs) {
68            long silentTime = sub.from - lastEnd;
69            if (silentTime > 0) {
70                samples.add(ByteBuffer.wrap(new byte[]{0, 0}));
71            } else if (silentTime < 0) {
72                throw new Error("Subtitle display times may not intersect");
73            }
74            ByteArrayOutputStream baos = new ByteArrayOutputStream();
75            DataOutputStream dos = new DataOutputStream(baos);
76            try {
77                dos.writeShort(sub.text.getBytes("UTF-8").length);
78                dos.write(sub.text.getBytes("UTF-8"));
79                dos.close();
80            } catch (IOException e) {
81                throw new Error("VM is broken. Does not support UTF-8");
82            }
83            samples.add(ByteBuffer.wrap(baos.toByteArray()));
84            lastEnd = sub.to;
85        }
86        return samples;
87    }
88
89    public SampleDescriptionBox getSampleDescriptionBox() {
90        return sampleDescriptionBox;
91    }
92
93    public List<TimeToSampleBox.Entry> getDecodingTimeEntries() {
94        List<TimeToSampleBox.Entry> stts = new LinkedList<TimeToSampleBox.Entry>();
95        long lastEnd = 0;
96        for (Line sub : subs) {
97            long silentTime = sub.from - lastEnd;
98            if (silentTime > 0) {
99                stts.add(new TimeToSampleBox.Entry(1, silentTime));
100            } else if (silentTime < 0) {
101                throw new Error("Subtitle display times may not intersect");
102            }
103            stts.add(new TimeToSampleBox.Entry(1, sub.to - sub.from));
104            lastEnd = sub.to;
105        }
106        return stts;
107    }
108
109    public List<CompositionTimeToSample.Entry> getCompositionTimeEntries() {
110        return null;
111    }
112
113    public long[] getSyncSamples() {
114        return null;
115    }
116
117    public List<SampleDependencyTypeBox.Entry> getSampleDependencies() {
118        return null;
119    }
120
121    public TrackMetaData getTrackMetaData() {
122        return trackMetaData;
123    }
124
125    public String getHandler() {
126        return "text";
127    }
128
129
130    public static class Line {
131        long from;
132        long to;
133        String text;
134
135
136        public Line(long from, long to, String text) {
137            this.from = from;
138            this.to = to;
139            this.text = text;
140        }
141
142        public long getFrom() {
143            return from;
144        }
145
146        public String getText() {
147            return text;
148        }
149
150        public long getTo() {
151            return to;
152        }
153    }
154
155    public Box getMediaHeaderBox() {
156        GenericMediaHeaderAtom ghmd = new GenericMediaHeaderAtom();
157        ghmd.addBox(new BaseMediaInfoAtom());
158        ghmd.addBox(new GenericMediaHeaderTextAtom());
159        return ghmd;
160    }
161
162    public SubSampleInformationBox getSubsampleInformationBox() {
163        return null;
164    }
165}
166