Имеется веб-приложение использующее 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
ОтветитьУдалить