Имеется веб-приложение использующее Xuggler для конвертации видео в flv и видео-файл записанный iPhone в портетном режиме. Видео конвертируется успешно, но в результате повернуто на 90 градусов. В таких видео с мобильных устройств фиксируется информация об ориентации записи (угол поворота камеры). QuickTime при воспроизведении определяет и поворачивает видео как нужно. Другие опробованные плееры (VLC, Kaffeine, MPlayer) автоматически видео не поворачивают. Попробовал вывести в эхо печать все метатеги и проперти имеющегося видеофайла. Потом погуглил, поискал.
Нашел что такая инфа относится к EXIF data и используется она не только в изображениях, но и в видео. В видеофайлах EXIF можно прочитать с помощью замечательной утилиты MediaInfo. Она то и показала, что параметр rotation (угол поворота в градусах) хранится в медиатегах видеопотока, а я то искал в контейнере файла :).
Осталось только повернуть кадры на нужный угол rotation (в данном примере я делаю еще и ресайз под нужный размер с учетом пропорций исходного видео). Надеюсь кому-нить еще пригодится:
PS. Скорее всего, видео с других мобильных устройств потребует аналогичной обработки для правильного определения угла поворота видео.
Нашел что такая инфа относится к EXIF data и используется она не только в изображениях, но и в видео. В видеофайлах EXIF можно прочитать с помощью замечательной утилиты MediaInfo. Она то и показала, что параметр rotation (угол поворота в градусах) хранится в медиатегах видеопотока, а я то искал в контейнере файла :).
Осталось только повернуть кадры на нужный угол rotation (в данном примере я делаю еще и ресайз под нужный размер с учетом пропорций исходного видео). Надеюсь кому-нить еще пригодится:
public class MultimediaContentConverterVideo{
public void convertOriginal(String urlIn, String urlOut, boolean debug) throws IOException {
String workingPath = FilenameUtils.getFullPath(urlIn);
String filenamePrefix = FilenameUtils.getBaseName(urlIn);
// create a media reader
IMediaReader reader = ToolFactory.makeReader(urlIn);
// stipulate that we want BufferedImages created in BGR 24bit color space
reader.setBufferedImageTypeToGenerate(BufferedImage.TYPE_3BYTE_BGR);
// create a writer which receives the decoded media from
// reader, encodes it and writes it out to the specified file
IMediaWriter writer = ToolFactory.makeWriter(urlOut, reader);
// add a debug listener to the writer to see media writer events
if (debug) {
writer.addListener(ToolFactory.makeDebugListener());
}
// read and decode packets from the source file and
// then encode and write out data to the output file
VideoRotator rotator = new VideoRotator();
reader.addListener(rotator);
rotator.addListener(writer);
while (reader.readPacket() == null);
}
private class VideoRotator extends MediaToolAdapter {
private int rotate = 0;
@Override
public void onVideoPicture(IVideoPictureEvent event) {
if (rotate != 0) {
BufferedImage img = event.getImage();
// rotate
double theta = Math.PI / 180 * rotate;
int widthRotated = (img.getWidth() >= img.getHeight()) ? img.getWidth() : img.getHeight();
int heightRotated = (img.getWidth() >= img.getHeight()) ? img.getWidth() : img.getHeight();
BufferedImage imgRotated = new BufferedImage(widthRotated, heightRotated, img.getType());
Graphics2D gRotate = imgRotated.createGraphics();
AffineTransform transform = new AffineTransform();
transform.rotate(theta, widthRotated / 2, heightRotated / 2);
transform.translate((widthRotated - img.getWidth()) / 2, (heightRotated - img.getHeight()) / 2);
gRotate.drawImage(img, transform, null);
gRotate.dispose();
// resize
int widthResized = widthRotated;
int heightResized = heightRotated;
if (heightResized > img.getHeight()) {
widthResized = Math.round((1.0f * img.getHeight() / heightResized) * widthResized);
heightResized = img.getHeight();
} else if (widthResized > img.getWidth()) {
heightResized = Math.round((1.0f * img.getWidth() / widthResized) * heightResized);
widthResized = img.getWidth();
}
Graphics2D g = img.createGraphics();
g.setColor(Color.BLACK);
g.fillRect(0, 0, img.getWidth(), img.getHeight());
g.drawImage(imgRotated, (img.getWidth() - widthResized) / 2, (img.getHeight() - heightResized) / 2, widthResized, heightResized, null);
g.dispose();
}
super.onVideoPicture(event);
}
@Override
public void onAddStream(IAddStreamEvent event) {
int streamIndex = event.getStreamIndex();
IStream stream = event.getSource().getContainer().getStream(streamIndex);
IStreamCoder streamCoder = event.getSource().getContainer().getStream(streamIndex).getStreamCoder();
if (streamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_AUDIO) {
streamCoder.setSampleRate(44100);
} else if (streamCoder.getCodecType() == ICodec.Type.CODEC_TYPE_VIDEO) {
String metaRotate = stream.getMetaData().getValue(META_KEY_ROTATE);
if (metaRotate != null && metaRotate.matches("\\d+")) {
rotate = Integer.valueOf(metaRotate);
}
}
super.onAddStream(event);
}
}
}
PS. Скорее всего, видео с других мобильных устройств потребует аналогичной обработки для правильного определения угла поворота видео.
What is the META_KEY_ROTATE value?
ОтветитьУдалитьpublic static String META_KEY_ROTATE = "rotate";
УдалитьThank you very much for posting, this is exactly what I needed
ОтветитьУдалить