mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Add DVB subtitles support
This commit is contained in:
parent
42629701f8
commit
d8f61ad7e7
@ -178,7 +178,11 @@ public class Cue {
|
||||
public final int windowColor;
|
||||
|
||||
/**
|
||||
* Creates an image cue.
|
||||
* The Storage Aspect Ratio of the Cue
|
||||
*/
|
||||
public final float sar;
|
||||
|
||||
/** * Creates an image cue.
|
||||
*
|
||||
* @param bitmap See {@link #bitmap}.
|
||||
* @param horizontalPosition The position of the horizontal anchor within the viewport, expressed
|
||||
@ -194,7 +198,28 @@ public class Cue {
|
||||
public Cue(Bitmap bitmap, float horizontalPosition, @AnchorType int horizontalPositionAnchor,
|
||||
float verticalPosition, @AnchorType int verticalPositionAnchor, float width) {
|
||||
this(null, null, bitmap, verticalPosition, LINE_TYPE_FRACTION, verticalPositionAnchor,
|
||||
horizontalPosition, horizontalPositionAnchor, width, false, Color.BLACK);
|
||||
horizontalPosition, horizontalPositionAnchor, width, false, Color.BLACK, (float) 1.7777);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an image cue.
|
||||
*
|
||||
* @param bitmap See {@link #bitmap}.
|
||||
* @param horizontalPosition The position of the horizontal anchor within the viewport, expressed
|
||||
* as a fraction of the viewport width.
|
||||
* @param horizontalPositionAnchor The horizontal anchor. One of {@link #ANCHOR_TYPE_START},
|
||||
* {@link #ANCHOR_TYPE_MIDDLE}, {@link #ANCHOR_TYPE_END} and {@link #TYPE_UNSET}.
|
||||
* @param verticalPosition The position of the vertical anchor within the viewport, expressed as a
|
||||
* fraction of the viewport height.
|
||||
* @param verticalPositionAnchor The vertical anchor. One of {@link #ANCHOR_TYPE_START},
|
||||
* {@link #ANCHOR_TYPE_MIDDLE}, {@link #ANCHOR_TYPE_END} and {@link #TYPE_UNSET}.
|
||||
* @param width The width of the cue, expressed as a fraction of the viewport width.
|
||||
* @param sar The Storage Aspect Ratio of the cue, defaults to FHD SAR unless otherwise specified.
|
||||
*/
|
||||
public Cue(Bitmap bitmap, float horizontalPosition, @AnchorType int horizontalPositionAnchor,
|
||||
float verticalPosition, @AnchorType int verticalPositionAnchor, float width, float sar) {
|
||||
this(null, null, bitmap, verticalPosition, LINE_TYPE_FRACTION, verticalPositionAnchor,
|
||||
horizontalPosition, horizontalPositionAnchor, width, false, Color.BLACK, sar);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -243,12 +268,12 @@ public class Cue {
|
||||
@AnchorType int lineAnchor, float position, @AnchorType int positionAnchor, float size,
|
||||
boolean windowColorSet, int windowColor) {
|
||||
this(text, textAlignment, null, line, lineType, lineAnchor, position, positionAnchor, size,
|
||||
windowColorSet, windowColor);
|
||||
windowColorSet, windowColor, 1);
|
||||
}
|
||||
|
||||
private Cue(CharSequence text, Alignment textAlignment, Bitmap bitmap, float line,
|
||||
@LineType int lineType, @AnchorType int lineAnchor, float position,
|
||||
@AnchorType int positionAnchor, float size, boolean windowColorSet, int windowColor) {
|
||||
@AnchorType int positionAnchor, float size, boolean windowColorSet, int windowColor, float sar) {
|
||||
this.text = text;
|
||||
this.textAlignment = textAlignment;
|
||||
this.bitmap = bitmap;
|
||||
@ -260,6 +285,7 @@ public class Cue {
|
||||
this.size = size;
|
||||
this.windowColorSet = windowColorSet;
|
||||
this.windowColor = windowColor;
|
||||
this.sar = sar;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -25,6 +25,8 @@ import com.google.android.exoplayer2.text.webvtt.Mp4WebvttDecoder;
|
||||
import com.google.android.exoplayer2.text.webvtt.WebvttDecoder;
|
||||
import com.google.android.exoplayer2.util.MimeTypes;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A factory for {@link SubtitleDecoder} instances.
|
||||
*/
|
||||
@ -83,6 +85,8 @@ public interface SubtitleDecoderFactory {
|
||||
} else if (format.sampleMimeType.equals(MimeTypes.APPLICATION_CEA708)) {
|
||||
return clazz.asSubclass(SubtitleDecoder.class).getConstructor(Integer.TYPE)
|
||||
.newInstance(format.accessibilityChannel);
|
||||
} else if (format.sampleMimeType.equals(MimeTypes.APPLICATION_DVBSUBS) && format.initializationData != null) {
|
||||
return clazz.asSubclass(SubtitleDecoder.class).getConstructor(List.class).newInstance(format.initializationData);
|
||||
} else {
|
||||
return clazz.asSubclass(SubtitleDecoder.class).getConstructor().newInstance();
|
||||
}
|
||||
@ -112,6 +116,8 @@ public interface SubtitleDecoderFactory {
|
||||
return Class.forName("com.google.android.exoplayer2.text.cea.Cea608Decoder");
|
||||
case MimeTypes.APPLICATION_CEA708:
|
||||
return Class.forName("com.google.android.exoplayer2.text.cea.Cea708Decoder");
|
||||
case MimeTypes.APPLICATION_DVBSUBS:
|
||||
return Class.forName("com.google.android.exoplayer2.text.dvbsubs.DvbSubsDecoder");
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
package com.google.android.exoplayer2.text.dvbsubs;
|
||||
|
||||
import com.google.android.exoplayer2.text.SimpleSubtitleDecoder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class DvbSubsDecoder extends SimpleSubtitleDecoder {
|
||||
private final String TAG = "DVBSubs Decoder";
|
||||
|
||||
private int subtitilingType;
|
||||
private int subtitleCompositionPage;
|
||||
private int subtitleAncillaryPage;
|
||||
private String subtitleContainer;
|
||||
|
||||
private int flags = 0;
|
||||
|
||||
DvbSubtitlesParser parser;
|
||||
|
||||
public DvbSubsDecoder() {
|
||||
super("dvbsubs");
|
||||
parser = new DvbSubtitlesParser();
|
||||
}
|
||||
|
||||
public DvbSubsDecoder(List<byte[]> initializationData) {
|
||||
super("dvbsubs");
|
||||
|
||||
byte[] tempByteArray;
|
||||
|
||||
tempByteArray = initializationData.get(0);
|
||||
subtitilingType = tempByteArray != null ? tempByteArray[0] & 0xFF: -1;
|
||||
|
||||
tempByteArray = initializationData.get(3);
|
||||
if (tempByteArray != null ) {
|
||||
subtitleContainer = new String(tempByteArray);
|
||||
if (subtitleContainer.equals("mkv")) {
|
||||
flags |= DvbSubtitlesParser.FLAG_PES_STRIPPED_DVBSUB;
|
||||
}
|
||||
}
|
||||
|
||||
if ((tempByteArray = initializationData.get(1)) != null) {
|
||||
this.subtitleCompositionPage = ((tempByteArray[0] & 0xFF) << 8) | (tempByteArray[1] & 0xFF);
|
||||
if ((tempByteArray = initializationData.get(2)) != null) {
|
||||
this.subtitleAncillaryPage = ((tempByteArray[0] & 0xFF) << 8) | (tempByteArray[1] & 0xFF);
|
||||
parser = new DvbSubtitlesParser(this.subtitleCompositionPage, this.subtitleAncillaryPage, flags);
|
||||
}
|
||||
} else {
|
||||
parser = new DvbSubtitlesParser();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DvbSubsSubtitle decode(byte[] data, int length) {
|
||||
return new DvbSubsSubtitle(parser.dvbSubsDecode(data, length));
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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.
|
||||
*/
|
||||
package com.google.android.exoplayer2.text.dvbsubs;
|
||||
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.text.Cue;
|
||||
import com.google.android.exoplayer2.text.Subtitle;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
final class DvbSubsSubtitle implements Subtitle {
|
||||
private final List<Cue> cues;
|
||||
|
||||
public DvbSubsSubtitle(Bitmap data) {
|
||||
if (data == null) {
|
||||
this.cues = Collections.emptyList();
|
||||
} else {
|
||||
Cue cue = new Cue(data, 0, Cue.ANCHOR_TYPE_START, 0, Cue.ANCHOR_TYPE_START, 1, (float) data.getWidth()/data.getHeight());
|
||||
this.cues = Collections.singletonList(cue);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNextEventTimeIndex(long timeUs) {
|
||||
return C.INDEX_UNSET;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getEventTimeCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getEventTime(int index) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Cue> getCues(long timeUs) {
|
||||
return cues;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -81,6 +81,7 @@ public final class MimeTypes {
|
||||
public static final String APPLICATION_SCTE35 = BASE_TYPE_APPLICATION + "/x-scte35";
|
||||
public static final String APPLICATION_CAMERA_MOTION = BASE_TYPE_APPLICATION + "/x-camera-motion";
|
||||
public static final String APPLICATION_EMSG = BASE_TYPE_APPLICATION + "/x-emsg";
|
||||
public static final String APPLICATION_DVBSUBS = BASE_TYPE_APPLICATION + "/dvbsubs";
|
||||
|
||||
private MimeTypes() {}
|
||||
|
||||
@ -222,7 +223,7 @@ public final class MimeTypes {
|
||||
|| APPLICATION_SUBRIP.equals(mimeType) || APPLICATION_TTML.equals(mimeType)
|
||||
|| APPLICATION_TX3G.equals(mimeType) || APPLICATION_MP4VTT.equals(mimeType)
|
||||
|| APPLICATION_RAWCC.equals(mimeType) || APPLICATION_VOBSUB.equals(mimeType)
|
||||
|| APPLICATION_PGS.equals(mimeType)) {
|
||||
|| APPLICATION_PGS.equals(mimeType) || APPLICATION_DVBSUBS.equals(mimeType)) {
|
||||
return C.TRACK_TYPE_TEXT;
|
||||
} else if (APPLICATION_ID3.equals(mimeType)
|
||||
|| APPLICATION_EMSG.equals(mimeType)
|
||||
|
@ -77,6 +77,7 @@ import com.google.android.exoplayer2.util.Util;
|
||||
@Cue.AnchorType
|
||||
private int cuePositionAnchor;
|
||||
private float cueSize;
|
||||
private float cueSar;
|
||||
private boolean applyEmbeddedStyles;
|
||||
private int foregroundColor;
|
||||
private int backgroundColor;
|
||||
@ -173,6 +174,7 @@ import com.google.android.exoplayer2.util.Util;
|
||||
&& this.cuePosition == cue.position
|
||||
&& Util.areEqual(this.cuePositionAnchor, cue.positionAnchor)
|
||||
&& this.cueSize == cue.size
|
||||
&& this.cueSar == cue.sar
|
||||
&& this.applyEmbeddedStyles == applyEmbeddedStyles
|
||||
&& this.foregroundColor == style.foregroundColor
|
||||
&& this.backgroundColor == style.backgroundColor
|
||||
@ -200,6 +202,7 @@ import com.google.android.exoplayer2.util.Util;
|
||||
this.cuePosition = cue.position;
|
||||
this.cuePositionAnchor = cue.positionAnchor;
|
||||
this.cueSize = cue.size;
|
||||
this.cueSar = cue.sar;
|
||||
this.applyEmbeddedStyles = applyEmbeddedStyles;
|
||||
this.foregroundColor = style.foregroundColor;
|
||||
this.backgroundColor = style.backgroundColor;
|
||||
@ -312,7 +315,7 @@ import com.google.android.exoplayer2.util.Util;
|
||||
float anchorX = parentLeft + (parentWidth * cuePosition);
|
||||
float anchorY = parentTop + (parentHeight * cueLine);
|
||||
int width = Math.round(parentWidth * cueSize);
|
||||
int height = Math.round(width * ((float) cueBitmap.getHeight() / cueBitmap.getWidth()));
|
||||
int height = Math.round(width * ((float) cueBitmap.getHeight() / cueBitmap.getWidth()) / (((float) parentWidth / parentHeight) / cueSar));
|
||||
int x = Math.round(cueLineAnchor == Cue.ANCHOR_TYPE_END ? (anchorX - width)
|
||||
: cueLineAnchor == Cue.ANCHOR_TYPE_MIDDLE ? (anchorX - (width / 2)) : anchorX);
|
||||
int y = Math.round(cuePositionAnchor == Cue.ANCHOR_TYPE_END ? (anchorY - height)
|
||||
|
Loading…
x
Reference in New Issue
Block a user