Javacv: Using FFmpegFrameFilter to rotate and set padding results in black and white image with green/purple blurs

Created on 17 Apr 2016  路  8Comments  路  Source: bytedeco/javacv

The goal I have is to broadcast to a RTMP server and that is going perfect in landscape mode. When I record in portrait mode, the resolution remains the same as in landscape (1280x720) and to prevent the video from becoming stretched out, I use the FFmpegFrameFilter to make changes to the video. I rotate the image, scale it and set padding to 'simulate' black bars like this:

filter = new FFmpegFrameFilter("transpose=2, scale=480:720, pad=1280:720:400:0:color=black", imageWidth, imageHeight);

The size of the new video looks about right, but the video is in black and white instead of color and there are green/purple blurs on the left/right edges of the video.

I have set the pixel format to AV_PIX_FMT_NV21, but that does not resolve the issue. If I delete the "pad=1280:720:400:0:color=black" part, the video does remain in color, but the image is all stretched out.

Once the orientation changes:

@Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);

        if(recorder != null) {
            if(newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
                filter = new FFmpegFrameFilter("transpose=2, scale=-1:720", imageWidth, imageHeight);
                filter.setPixelFormat(avutil.AV_PIX_FMT_NV21); // default camera format on Android
                try {
                    filter.start();
                } catch (FrameFilter.Exception e) {
                    e.printStackTrace();
                }
            }

            else {
                filter = null;
            }
        }
    }

OnPreviewFrame:

@Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            if (audioRecord == null || audioRecord.getRecordingState() != AudioRecord.RECORDSTATE_RECORDING) {
                startTime = System.currentTimeMillis();
                return;
            }
            if (RECORD_LENGTH > 0) {
                int i = imagesIndex++ % images.length;
                yuvImage = images[i];
                timestamps[i] = 1000 * (System.currentTimeMillis() - startTime);
            }
            /* get video data */
            if (yuvImage != null && recording) {
                ((ByteBuffer)yuvImage.image[0].position(0)).put(data);

                if (RECORD_LENGTH <= 0) try {
                    Log.v(LOG_TAG,"Writing Frame");
                    long t = 1000 * (System.currentTimeMillis() - startTime);
                    if (t > recorder.getTimestamp()) {
                        recorder.setTimestamp(t);
                    }

                    if(filter != null) {
                        try {
                            filter.push(yuvImage);
                            Frame frame;
                            while ((frame = filter.pull()) != null) {
                                recorder.record(frame);
                            }
                        } catch (FrameFilter.Exception e) {
                            e.printStackTrace();
                        }
                    }

                    else {
                        recorder.record(yuvImage);
                    }
                } catch (FFmpegFrameRecorder.Exception e) {
                    Log.v(LOG_TAG,e.getMessage());
                    e.printStackTrace();
                }
            }
        }
    }

Do you have any suggestions?

question

Most helpful comment

Hey thanks @saudet , turns out the problem was in the "pad" filter (perhaps it's a support issue with the pixel formats like you suggested)...
I've ended up using the "crop" filter instead, which works very nicely. Here's my full portrait mode filter so far:

String transpose = cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT ? "2" : "1";
String scale = "-1:ih";
String crop = "iw:ih:(ow-iw)/2:0";
filter = new FFmpegFrameFilter("transpose=" + transpose + ", scale=" + scale + ", crop=" + crop, imageWidth, imageHeight);
filter.setPixelFormat(avutil.AV_PIX_FMT_NV21);

All 8 comments

Is this an issue with FFmpegFrameFilter? Or is it a question about FFmpeg filters?

This is not a question about FFmpeg filters, but a question about FFmpegFrameFilter. I just tried a similar command with regular FFmpeg and it worked fine, so looks like it's an issue with FFmpegFrameFilter.

I know some filters don't support all pixel formats very well, so you might want to try and use a different one. It's possible to do conversion within the graph with the format filter:
https://ffmpeg.org/ffmpeg-filters.html#format-1
https://github.com/bytedeco/javacv/issues/232#issuecomment-162601656

Have you been able to find the right combination of filters to get this working?

Hi,

No I've been unable to get it working. In the end I've decided to use Kickflip for my project.

Thanks for your help though!

I'm also experiencing the same issue. I've been trying all sorts of combinations of filters and formats, so far no luck.
Did anybody find a decent solution for this?

Try to put "format=rgba" and/or "format=bgr24" filters at various stages in the graph...

Hey thanks @saudet , turns out the problem was in the "pad" filter (perhaps it's a support issue with the pixel formats like you suggested)...
I've ended up using the "crop" filter instead, which works very nicely. Here's my full portrait mode filter so far:

String transpose = cameraId == Camera.CameraInfo.CAMERA_FACING_FRONT ? "2" : "1";
String scale = "-1:ih";
String crop = "iw:ih:(ow-iw)/2:0";
filter = new FFmpegFrameFilter("transpose=" + transpose + ", scale=" + scale + ", crop=" + crop, imageWidth, imageHeight);
filter.setPixelFormat(avutil.AV_PIX_FMT_NV21);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

chenhl05 picture chenhl05  路  4Comments

fif10 picture fif10  路  3Comments

SenudaJayalath picture SenudaJayalath  路  3Comments

nghiepvth picture nghiepvth  路  3Comments

Maleandr picture Maleandr  路  3Comments