package org.jcodec.api.awt; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.awt.image.BufferedImage; import java.io.IOException; import java.util.Arrays; import org.jcodec.api.JCodecException; import org.jcodec.api.specific.ContainerAdaptor; import org.jcodec.common.Codec; import org.jcodec.common.DemuxerTrackMeta; import org.jcodec.common.SeekableDemuxerTrack; import org.jcodec.common.TrackType; import org.jcodec.common.VideoCodecMeta; import org.jcodec.common.model.ColorSpace; import org.jcodec.common.model.Packet; import org.jcodec.common.model.Packet.FrameType; import org.jcodec.common.model.Picture8Bit; import org.jcodec.common.model.Size; import org.jcodec.containers.mp4.MP4Packet; import org.junit.Assert; import org.junit.Test; import org.mockito.InOrder; public class FrameGrab8BitTest { private static final Class<? extends byte[][]> BYTE_DOUBLE_ARRAY_CLASS = new byte[0][0].getClass(); @Test public void testGetFrame() throws IOException { ContainerAdaptor adaptor = mock(ContainerAdaptor.class); SeekableDemuxerTrack videoTrack = mock(SeekableDemuxerTrack.class); AWTFrameGrab8Bit grab = new AWTFrameGrab8Bit(videoTrack, adaptor); Picture8Bit pic = Picture8Bit.create(16, 16, ColorSpace.YUV420J); Arrays.fill(pic.getPlaneData(0), (byte) (169 - 128)); Arrays.fill(pic.getPlaneData(1), (byte) (45 - 128)); Arrays.fill(pic.getPlaneData(2), (byte) (103 - 128)); MP4Packet packet = new MP4Packet(null, 0, 25, 1, 0, FrameType.KEY, null, 0, 0, 0, 0, 42, true); when(adaptor.decodeFrame8Bit(any(Packet.class), any(BYTE_DOUBLE_ARRAY_CLASS))).thenReturn(pic); when(videoTrack.nextFrame()).thenReturn(packet); BufferedImage res = grab.getFrame(); verify(videoTrack).nextFrame(); verify(adaptor).decodeFrame8Bit(eq(packet), any(BYTE_DOUBLE_ARRAY_CLASS)); for (int i = 0; i < 256; i++) { int rgb = res.getRGB(i % 16, i / 16); Assert.assertEquals(134, (rgb >> 16) & 0xff); Assert.assertEquals(215, (rgb >> 8) & 0xff); Assert.assertEquals(22, (rgb) & 0xff); } } @Test public void testSeekSloppy() throws IOException, JCodecException { ContainerAdaptor adaptor = mock(ContainerAdaptor.class); SeekableDemuxerTrack videoTrack = mock(SeekableDemuxerTrack.class); AWTFrameGrab8Bit grab = new AWTFrameGrab8Bit(videoTrack, adaptor); int[] keyFrames = new int[] { 0, 11, 25, 34, 48, 59, 100 }; DemuxerTrackMeta meta = new DemuxerTrackMeta(TrackType.VIDEO, Codec.H264, 120, keyFrames, 120, null, new VideoCodecMeta(new Size(320, 240), ColorSpace.YUV420), null); when(videoTrack.getMeta()).thenReturn(meta); when(videoTrack.getCurFrame()).thenReturn(42L); grab.seekToFrameSloppy(42); verify(videoTrack).gotoFrame(42); verify(videoTrack).gotoFrame(34); } @Test public void testSeekPrecise() throws IOException, JCodecException { ContainerAdaptor adaptor = mock(ContainerAdaptor.class); SeekableDemuxerTrack videoTrack = mock(SeekableDemuxerTrack.class); AWTFrameGrab8Bit grab = new AWTFrameGrab8Bit(videoTrack, adaptor); int[] keyFrames = new int[] { 0, 11, 25, 40, 48, 59, 100 }; DemuxerTrackMeta meta = new DemuxerTrackMeta(TrackType.VIDEO, Codec.H264, 120, keyFrames, 120, null, new VideoCodecMeta(new Size(320, 240), ColorSpace.YUV420), null); MP4Packet frame40 = new MP4Packet(null, 40, 25, 1, 40, FrameType.KEY, null, 0, 0, 0, 0, 42, true); MP4Packet frame41 = new MP4Packet(null, 41, 25, 1, 41, FrameType.KEY, null, 0, 0, 0, 0, 42, true); MP4Packet frame42 = new MP4Packet(null, 42, 25, 1, 42, FrameType.KEY, null, 0, 0, 0, 0, 42, true); when(videoTrack.getMeta()).thenReturn(meta); when(videoTrack.getCurFrame()).thenReturn(42L); when(videoTrack.nextFrame()).thenReturn(frame40).thenReturn(frame41).thenReturn(frame42); grab.seekToFramePrecise(42); InOrder o = inOrder(adaptor, videoTrack); o.verify(adaptor).decodeFrame8Bit(eq(frame40), any(BYTE_DOUBLE_ARRAY_CLASS)); o.verify(adaptor).decodeFrame8Bit(eq(frame41), any(BYTE_DOUBLE_ARRAY_CLASS)); } }