-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
I am trying to cut and store certain part of a video, keeping the resolution and frame size the same. However, in some videos (mostly recorded by phones), the metadata "rotate" is not zero. For example, if the video is recorded with the phone held horizontally, the resulting video could have metadata "rotate" 270 or 90.
When editing videos like this, FFmpegFrameGrabber automatically rotates the video when grabbing. Is there a way to undo this? i.e. I want the video the way it is no matter what the metadata "rotate" says.
I have read other issues where FFmpegFrameFilter is recommended to be used to rotate the image back to normal. I have tried this, but the resulting video is never the same (either stretched or compressed, looking weird). For example, one of my original video has resolution 1280 * 592, metadata "rotate" is 270. The grabber has imageWidth automatically set as 592 and imageHeight 1280 (it should be the other way around). In the filter and recorder, I manually set the imageWidth to 1280 and imageHeight to 592, and give filters "transpose=cclock. " The resulting video is indeed 1280 * 592, but dramatically stretched and looks very different from the original one. Below is my code.
// both start and end are in seconds, the test case cut from 0 to 60 seconds.
private static File cutVideo(File video, long start, long end) {
FFmpegFrameGrabber grabber = new FFmpegFrameGrabber(video);
grabber.setOption("rw_timeout", String.valueOf(getVideoTime(video) * 1000 * 1000 * 2));
grabber.setOption("rtsp_transport", "tcp");
File outputFile = new File("test.mp4");
try {
grabber.start();
log.info("ImageWidth:" + grabber.getImageWidth());
log.info("ImageHeight:" + grabber.getImageHeight());
log.info("AudioChannels:" + grabber.getAudioChannels());
log.info("Format:" + grabber.getFormat());
log.info("Rotation angle: " + grabber.getVideoMetadata("rotate"));
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder(outputFile, grabber.getImageWidth(),
grabber.getImageHeight(), grabber.getAudioChannels());
recorder.setFrameRate(grabber.getFrameRate());
recorder.setPixelFormat(AV_PIX_FMT_YUV420P);
recorder.setAudioCodecName("aac");
recorder.setVideoCodec(grabber.getVideoCodec());
recorder.setFormat("mp4");
grabAndRecord(recorder, grabber, start, end);
} catch (Exception e) {
e.printStackTrace();
}
return outputFile;
}
private static void grabAndRecord(FFmpegFrameRecorder recorder, FFmpegFrameGrabber grabber, long start, long end) throws Exception {
grabber.setTimestamp(start * 1000000);
Frame nextFrame = null;
String rotate = grabber.getVideoMetadata("rotate");
if (rotate != null && rotate.length() > 1) {
FFmpegFrameFilter filter = null;
switch(rotate){
case "90":
filter = new FFmpegFrameFilter("transpose=clock", grabber.getImageHeight(),
grabber.getImageWidth());
recorder.setImageHeight(filter.getImageHeight());
recorder.setImageWidth(filter.getImageWidth());
break;
case "180":
filter = new FFmpegFrameFilter("rotate=PI", grabber.getImageWidth(),
grabber.getImageHeight());
break;
case "270":
filter = new FFmpegFrameFilter("transpose=cclock", grabber.getImageHeight(),
grabber.getImageWidth());
recorder.setImageHeight(filter.getImageHeight());
recorder.setImageWidth(filter.getImageWidth());
break;
}
filter.setPixelFormat(grabber.getPixelFormat());
filter.setFrameRate(grabber.getFrameRate());
filter.start();
nextFrame = grabber.grabImage();
filter.push(nextFrame);
Frame filteredFrame = null;
recorder.start();
while (grabber.getTimestamp() <= end * 1000000 && (filteredFrame = filter.pull()) != null) {
recorder.record(filteredFrame);
nextFrame = grabber.grabImage();
filter.push(nextFrame);
}
filter.stop();
filter.release();
} else {
recorder.start();
while (grabber.getTimestamp() <= end * 1000000 && (nextFrame = grabber.grabFrame()) != null) {
recorder.record(nextFrame);
}
}
recorder.stop();
recorder.release();
grabber.stop();
grabber.release();
}