java - 如何在 xuggler 中将旋转元数据写入视频?
问题描述
我创建了一个类来调整视频的大小。我用在我的手机上以纵向模式拍摄的视频对此进行了测试。视频在电话和计算机上的任何媒体播放器展位中以纵向模式正确显示。但是,当使用我的程序调整视频大小时,视频大小正确调整,但旋转元数据丢失。
通过 mediainfo 查询我的输入视频的元数据会得到以下输出:
General
Complete name : /home/sneese/Downloads/20190708_095754.mp4
Format : MPEG-4
Format profile : Base Media / Version 2
Codec ID : mp42 (isom/mp42)
File size : 22.7 MiB
Duration : 6s 741ms
Overall bit rate : 28.3 Mbps
Encoded date : UTC 2019-07-08 07:58:02
Tagged date : UTC 2019-07-08 07:58:02
com.android.version : 8.0.0
Video
ID : 1
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High@L4.2
Format settings, CABAC : Yes
Format settings, ReFrames : 1 frame
Format settings, GOP : M=1, N=60
Codec ID : avc1
Codec ID/Info : Advanced Video Coding
Duration : 6s 732ms
Bit rate : 28.0 Mbps
Width : 1 920 pixels
Height : 1 080 pixels
Display aspect ratio : 16:9
Rotation : 90°
Frame rate mode : Variable
Frame rate : 60.000 fps
Minimum frame rate : 59.094 fps
Maximum frame rate : 60.934 fps
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Bits/(Pixel*Frame) : 0.225
Stream size : 22.5 MiB (99%)
Title : VideoHandle
Language : English
Encoded date : UTC 2019-07-08 07:58:02
Tagged date : UTC 2019-07-08 07:58:02
mdhd_Duration : 6732
Audio
ID : 2
Format : AAC
Format/Info : Advanced Audio Codec
Format profile : LC
Codec ID : 40
Duration : 6s 741ms
Source duration : 6s 745ms
Source_Duration_FirstFrame : 3ms
Bit rate mode : Constant
Bit rate : 256 Kbps
Channel(s) : 2 channels
Channel positions : Front: L R
Sampling rate : 48.0 KHz
Frame rate : 46.875 fps (1024 spf)
Compression mode : Lossy
Stream size : 211 KiB (1%)
Source stream size : 211 KiB (1%)
Title : SoundHandle
Language : English
Encoded date : UTC 2019-07-08 07:58:02
Tagged date : UTC 2019-07-08 07:58:02
mdhd_Duration : 6741
如您所见,旋转设置为 90 度。
这是我的代码:
主类:包test.video;
import com.xuggle.mediatool.IMediaReader;
import com.xuggle.mediatool.IMediaWriter;
import com.xuggle.mediatool.ToolFactory;
import com.xuggle.xuggler.ICodec;
import com.xuggle.xuggler.IContainer;
import com.xuggle.xuggler.IMetaData;
import com.xuggle.xuggler.IStream;
import com.xuggle.xuggler.IStreamCoder;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Arrays;
public class MediaConverter {
private static final String INPUT_FILE = "/home/user/input_video.mp4";
private static final String OUTPUT_FILE = "/home/user/output_video.mp4";
public static void main(String[] args) throws IOException {
convertVideo(INPUT_FILE, OUTPUT_FILE, 640, 360);
}
private static void convertVideo(String inputFile, String outputFile, int width, int height){
// reader
IMediaReader reader = ToolFactory.makeReader(inputFile);
Resizer resizer = new Resizer(width, height);
reader.addListener(resizer);
// writer
IMediaWriter writer = ToolFactory.makeWriter(outputFile, reader);
resizer.addListener(writer);
while (reader.readPacket() == null) {
// no need to do anything here just let him read
}
writer.flush();
}
}
MediaToolAdapter:包test.video;
import com.xuggle.mediatool.MediaToolAdapter;
import com.xuggle.mediatool.event.IAddStreamEvent;
import com.xuggle.mediatool.event.IVideoPictureEvent;
import com.xuggle.mediatool.event.IWriteHeaderEvent;
import com.xuggle.mediatool.event.VideoPictureEvent;
import com.xuggle.xuggler.ICodec;
import com.xuggle.xuggler.IMetaData;
import com.xuggle.xuggler.IStream;
import com.xuggle.xuggler.IStreamCoder;
import com.xuggle.xuggler.IVideoPicture;
import com.xuggle.xuggler.IVideoResampler;
import java.util.Collection;
public class Resizer extends MediaToolAdapter {
private Integer width;
private Integer height;
private IVideoResampler videoResampler = null;
public Resizer(Integer aWidth, Integer aHeight) {
this.width = aWidth;
this.height = aHeight;
}
@Override
public void onAddStream(IAddStreamEvent event) {
int streamIndex = event.getStreamIndex();
IStreamCoder streamCoder = event.getSource().getContainer().getStream(streamIndex).getStreamCoder();
if (streamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
IStream stream = event.getSource().getContainer().getStream(streamIndex);
streamCoder.setWidth(width);
streamCoder.setHeight(height);
// checked if this writes the metadata - but does not
streamCoder.setProperty(stream.getMetaData(), null);
event.getSource().getContainer().setMetaData(stream.getMetaData());
}
super.onAddStream(event);
}
@Override
public void onVideoPicture(IVideoPictureEvent event) {
IVideoPicture pic = event.getPicture();
if (videoResampler == null) {
videoResampler = IVideoResampler.make(width, height, pic.getPixelType(), pic.getWidth(), pic
.getHeight(), pic.getPixelType());
}
IVideoPicture out = IVideoPicture.make(pic.getPixelType(), width, height);
videoResampler.resample(out, pic);
IVideoPictureEvent asc = new VideoPictureEvent(event.getSource(), out, event.getStreamIndex());
super.onVideoPicture(asc);
out.delete();
}
}
预期的结果是视频在转换后以纵向模式显示,如果它像转换之前的那样,否则为横向模式。谢谢
解决方案
推荐阅读
- mysql - 找不到外键格式错误的原因
- python - 搜索哪里出错了?
- javascript - 如何根据所选月份的天数隐藏表格中的列?
- python - 如何将输入从一个文件导入到另一个文件并同步?
- php - 在 Symfony 4 中设置多个内核
- html - 内容文本与我的固定标题重叠
- java - KerberosAuthenticationProvider 与 KerberosServiceAuthenticationProvider
- pandas - 无法将大型火花数据框保存为泡菜
- javascript - 如何在 HTML 元素之后放置文本光标?
- python - Numpy 3D 数组索引:适用于 2D,如何处理 3D?