17cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang/* 27cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * Copyright (C) 2018 The Android Open Source Project 37cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * 47cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * Licensed under the Apache License, Version 2.0 (the "License"); 57cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * you may not use this file except in compliance with the License. 67cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * You may obtain a copy of the License at 77cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * 87cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * http://www.apache.org/licenses/LICENSE-2.0 97cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * 107cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * Unless required by applicable law or agreed to in writing, software 117cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * distributed under the License is distributed on an "AS IS" BASIS, 127cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * See the License for the specific language governing permissions and 147cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * limitations under the License. 157cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang */ 167cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 17db1945bea4e3816a04afe0ad41681cec1d0c074dAlan Viverettepackage androidx.heifwriter; 187cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 197cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport static android.support.test.InstrumentationRegistry.getContext; 207cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 217cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.graphics.Bitmap; 227cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.graphics.ImageFormat; 237cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.media.MediaExtractor; 247cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.media.MediaFormat; 257cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.media.MediaMetadataRetriever; 267cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.opengl.GLES20; 277cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.os.Environment; 287cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.os.Handler; 297cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.os.HandlerThread; 307cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.os.Process; 317cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.support.test.filters.LargeTest; 327cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.support.test.runner.AndroidJUnit4; 337cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport android.util.Log; 34b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhang 35b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhangimport static androidx.heifwriter.HeifWriter.INPUT_MODE_BITMAP; 36b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhangimport static androidx.heifwriter.HeifWriter.INPUT_MODE_BUFFER; 37b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhangimport static androidx.heifwriter.HeifWriter.INPUT_MODE_SURFACE; 38b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhang 39b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhangimport androidx.annotation.NonNull; 40b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhangimport androidx.annotation.Nullable; 41db1945bea4e3816a04afe0ad41681cec1d0c074dAlan Viveretteimport androidx.heifwriter.test.R; 427cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 43b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhangimport static org.junit.Assert.assertEquals; 44b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhangimport static org.junit.Assert.assertTrue; 45b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhang 467cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport org.junit.After; 477cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport org.junit.Before; 487cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport org.junit.Test; 497cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport org.junit.runner.RunWith; 507cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 517cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport java.io.Closeable; 527cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport java.io.File; 537cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport java.io.FileInputStream; 547cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport java.io.FileOutputStream; 557cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport java.io.IOException; 567cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport java.io.InputStream; 577cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport java.io.OutputStream; 587cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangimport java.util.Arrays; 597cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 607cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang/** 617cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang * Test {@link HeifWriter}. 627cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang */ 637cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang@RunWith(AndroidJUnit4.class) 647cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhangpublic class HeifWriterTest { 657cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private static final String TAG = HeifWriterTest.class.getSimpleName(); 667cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private static final boolean DEBUG = false; 677cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private static final boolean DUMP_YUV_INPUT = false; 687cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 697cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private static byte[][] TEST_COLORS = { 707cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang {(byte) 255, (byte) 0, (byte) 0}, 717cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang {(byte) 255, (byte) 0, (byte) 255}, 727cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang {(byte) 255, (byte) 255, (byte) 255}, 737cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang {(byte) 255, (byte) 255, (byte) 0}, 747cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang }; 757cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 767cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private static final String TEST_HEIC = "test.heic"; 777cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private static final int[] IMAGE_RESOURCES = new int[] { 787cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang R.raw.test 797cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang }; 807cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private static final String[] IMAGE_FILENAMES = new String[] { 817cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang TEST_HEIC 827cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang }; 837cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private static final String OUTPUT_FILENAME = "output.heic"; 847cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 857cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private EglWindowSurface mInputEglSurface; 867cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private Handler mHandler; 877cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private int mInputIndex; 887cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 897cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Before 907cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void setUp() throws Exception { 917cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang for (int i = 0; i < IMAGE_RESOURCES.length; ++i) { 927cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang String outputPath = new File(Environment.getExternalStorageDirectory(), 937cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang IMAGE_FILENAMES[i]).getAbsolutePath(); 947cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 957cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang InputStream inputStream = null; 967cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang FileOutputStream outputStream = null; 977cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang try { 987cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang inputStream = getContext().getResources().openRawResource(IMAGE_RESOURCES[i]); 997cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang outputStream = new FileOutputStream(outputPath); 1007cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang copy(inputStream, outputStream); 1017cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } finally { 1027cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang closeQuietly(inputStream); 1037cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang closeQuietly(outputStream); 1047cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1057cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1067cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1077cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang HandlerThread handlerThread = new HandlerThread( 1087cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang "HeifEncoderThread", Process.THREAD_PRIORITY_FOREGROUND); 1097cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang handlerThread.start(); 1107cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang mHandler = new Handler(handlerThread.getLooper()); 1117cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1127cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1137cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @After 1147cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void tearDown() throws Exception { 1157cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang for (int i = 0; i < IMAGE_RESOURCES.length; ++i) { 1167cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang String imageFilePath = 1177cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang new File(Environment.getExternalStorageDirectory(), IMAGE_FILENAMES[i]) 1187cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang .getAbsolutePath(); 1197cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang File imageFile = new File(imageFilePath); 1207cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (imageFile.exists()) { 1217cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang imageFile.delete(); 1227cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1237cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1247cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1257cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1267cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 1277cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 1287cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputBuffer_NoGrid_NoHandler() throws Throwable { 1295c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BUFFER, false, false); 1305c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder); 1317cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1327cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1337cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 1347cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 1357cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputBuffer_Grid_NoHandler() throws Throwable { 1365c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BUFFER, true, false); 1375c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder); 1387cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1397cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1407cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 1417cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 1427cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputBuffer_NoGrid_Handler() throws Throwable { 1435c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BUFFER, false, true); 1445c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder); 1457cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1467cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1477cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 1487cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 1497cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputBuffer_Grid_Handler() throws Throwable { 1505c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BUFFER, true, true); 1515c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder); 1527cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1537cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1547cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 1557cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 1567cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputSurface_NoGrid_NoHandler() throws Throwable { 1575c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, false, false); 1585c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder); 1597cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1607cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1617cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 1627cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 1637cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputSurface_Grid_NoHandler() throws Throwable { 1645c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, true, false); 1655c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder); 1667cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1677cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1687cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 1697cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 1707cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputSurface_NoGrid_Handler() throws Throwable { 1715c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, false, true); 1725c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder); 1737cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1747cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1757cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 1767cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 1777cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputSurface_Grid_Handler() throws Throwable { 1785c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_SURFACE, true, true); 1795c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder); 1807cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1817cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1827cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 1837cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 1847cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputBitmap_NoGrid_NoHandler() throws Throwable { 1855c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BITMAP, false, false); 1867cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang for (int i = 0; i < IMAGE_RESOURCES.length; ++i) { 1877cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang String inputPath = new File(Environment.getExternalStorageDirectory(), 1887cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang IMAGE_FILENAMES[i]).getAbsolutePath(); 1895c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder.setInputPath(inputPath)); 1907cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1917cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 1927cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1937cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 1947cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 1957cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputBitmap_Grid_NoHandler() throws Throwable { 1965c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BITMAP, true, false); 1977cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang for (int i = 0; i < IMAGE_RESOURCES.length; ++i) { 1987cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang String inputPath = new File(Environment.getExternalStorageDirectory(), 1997cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang IMAGE_FILENAMES[i]).getAbsolutePath(); 2005c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder.setInputPath(inputPath)); 2017cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2027cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2037cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 2047cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 2057cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 2067cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputBitmap_NoGrid_Handler() throws Throwable { 2075c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BITMAP, false, true); 2087cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang for (int i = 0; i < IMAGE_RESOURCES.length; ++i) { 2097cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang String inputPath = new File(Environment.getExternalStorageDirectory(), 2107cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang IMAGE_FILENAMES[i]).getAbsolutePath(); 2115c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder.setInputPath(inputPath)); 2127cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2137cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2147cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 2157cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Test 2167cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @LargeTest 2177cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public void testInputBitmap_Grid_Handler() throws Throwable { 2185c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig.Builder builder = new TestConfig.Builder(INPUT_MODE_BITMAP, true, true); 2197cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang for (int i = 0; i < IMAGE_RESOURCES.length; ++i) { 2207cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang String inputPath = new File(Environment.getExternalStorageDirectory(), 2217cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang IMAGE_FILENAMES[i]).getAbsolutePath(); 2225c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTestForVariousNumberImages(builder.setInputPath(inputPath)); 2237cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2247cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2257cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 2265c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang private void doTestForVariousNumberImages(TestConfig.Builder builder) throws Exception { 227c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang builder.setNumImages(4); 228c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang doTest(builder.setRotation(270).build()); 229c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang doTest(builder.setRotation(180).build()); 230c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang doTest(builder.setRotation(90).build()); 231c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang doTest(builder.setRotation(0).build()); 2325c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTest(builder.setNumImages(1).build()); 2335c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang doTest(builder.setNumImages(8).build()); 2345c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang } 2355c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang 2367cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private void closeQuietly(Closeable closeable) { 2377cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (closeable != null) { 2387cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang try { 2397cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang closeable.close(); 2407cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } catch (RuntimeException rethrown) { 2417cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang throw rethrown; 2427cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } catch (Exception ignored) { 2437cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2447cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2457cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2467cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 2477cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private int copy(InputStream in, OutputStream out) throws IOException { 2487cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang int total = 0; 2497cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang byte[] buffer = new byte[8192]; 2507cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang int c; 2517cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang while ((c = in.read(buffer)) != -1) { 2527cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang total += c; 2537cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang out.write(buffer, 0, c); 2547cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2557cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang return total; 2567cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2577cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 2587cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private static class TestConfig { 259c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final int mInputMode; 260c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final boolean mUseGrid; 261c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final boolean mUseHandler; 262c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final int mMaxNumImages; 263c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final int mNumImages; 264c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final int mWidth; 265c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final int mHeight; 266c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final int mRotation; 267c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final int mQuality; 268c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final String mInputPath; 269c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final String mOutputPath; 270c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final Bitmap[] mBitmaps; 271c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang 272c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang TestConfig(int inputMode, boolean useGrid, boolean useHandler, 273c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang int maxNumImages, int numImages, int width, int height, 274c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang int rotation, int quality, 275c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang String inputPath, String outputPath, Bitmap[] bitmaps) { 276c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mInputMode = inputMode; 277c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mUseGrid = useGrid; 278c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mUseHandler = useHandler; 279c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mMaxNumImages = maxNumImages; 280c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mNumImages = numImages; 281c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mWidth = width; 282c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mHeight = height; 283c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mRotation = rotation; 284c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mQuality = quality; 285c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mInputPath = inputPath; 286c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mOutputPath = outputPath; 287c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mBitmaps = bitmaps; 2887cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 2897cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 2905c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang static class Builder { 291c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final int mInputMode; 292c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final boolean mUseGrid; 293c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final boolean mUseHandler; 294c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang int mMaxNumImages; 295c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang int mNumImages; 296c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang int mWidth; 297c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang int mHeight; 298c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang int mRotation; 299c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final int mQuality; 300c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang String mInputPath; 301c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang final String mOutputPath; 302c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang Bitmap[] mBitmaps; 303c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang boolean mNumImagesSetExplicitly; 304c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang 305c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang 306c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang Builder(int inputMode, boolean useGrids, boolean useHandler) { 307c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mInputMode = inputMode; 308c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mUseGrid = useGrids; 309c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mUseHandler = useHandler; 310c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mMaxNumImages = mNumImages = 4; 311c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mWidth = 1920; 312c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mHeight = 1080; 313c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mRotation = 0; 314c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mQuality = 100; 315c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mOutputPath = new File(Environment.getExternalStorageDirectory(), 3165c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang OUTPUT_FILENAME).getAbsolutePath(); 3177cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 3185c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang 319c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang Builder setInputPath(String inputPath) { 320c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mInputPath = (mInputMode == INPUT_MODE_BITMAP) ? inputPath : null; 3215c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang return this; 3227cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 3235c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang 324c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang Builder setNumImages(int numImages) { 325c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mNumImagesSetExplicitly = true; 326c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mNumImages = numImages; 327c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang return this; 328c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang } 329c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang 330c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang Builder setRotation(int rotation) { 331c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mRotation = rotation; 3325c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang return this; 3337cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 3347cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 3355c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang private void loadBitmapInputs() { 336c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang if (mInputMode != INPUT_MODE_BITMAP) { 3375c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang return; 3385c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang } 3395c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 340c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang retriever.setDataSource(mInputPath); 3415c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang String hasImage = retriever.extractMetadata( 3425c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE); 3435c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang if (!"yes".equals(hasImage)) { 3445c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang throw new IllegalArgumentException("no bitmap found!"); 3455c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang } 346c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mMaxNumImages = Math.min(mMaxNumImages, Integer.parseInt(retriever.extractMetadata( 3475c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT))); 348c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang if (!mNumImagesSetExplicitly) { 349c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mNumImages = mMaxNumImages; 3505c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang } 351c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mBitmaps = new Bitmap[mMaxNumImages]; 352c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang for (int i = 0; i < mBitmaps.length; i++) { 353c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mBitmaps[i] = retriever.getImageAtIndex(i); 3545c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang } 355c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mWidth = mBitmaps[0].getWidth(); 356c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mHeight = mBitmaps[0].getHeight(); 3575c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang retriever.release(); 3585c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang } 3595c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang 3605c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang private void cleanupStaleOutputs() { 361c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang File outputFile = new File(mOutputPath); 3625c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang if (outputFile.exists()) { 3635c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang outputFile.delete(); 3645c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang } 3655c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang } 3665c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang 3675c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang TestConfig build() { 3685c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang cleanupStaleOutputs(); 3695c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang loadBitmapInputs(); 3705c0dcef896f803442eeca6aad3af8183f6e27071Chong Zhang 371c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang return new TestConfig(mInputMode, mUseGrid, mUseHandler, mMaxNumImages, mNumImages, 372c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang mWidth, mHeight, mRotation, mQuality, mInputPath, mOutputPath, mBitmaps); 3737cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 3747cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 3757cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 3767cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Override 3777cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang public String toString() { 378c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang return "TestConfig" 379c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ": mInputMode " + mInputMode 380c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ", mUseGrid " + mUseGrid 381c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ", mUseHandler " + mUseHandler 382c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ", mMaxNumImages " + mMaxNumImages 383c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ", mNumImages " + mNumImages 384c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ", mWidth " + mWidth 385c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ", mHeight " + mHeight 386c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ", mRotation " + mRotation 387c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ", mQuality " + mQuality 388c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ", mInputPath " + mInputPath 389c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang + ", mOutputPath " + mOutputPath; 3907cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 3917cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 3927cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 393c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang private void doTest(TestConfig config) throws Exception { 394c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang int width = config.mWidth; 395c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang int height = config.mHeight; 396c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang int numImages = config.mNumImages; 3977cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 3987cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang mInputIndex = 0; 3997cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang HeifWriter heifWriter = null; 4007cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang FileInputStream inputStream = null; 4017cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang FileOutputStream outputStream = null; 4027cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang try { 403c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang if (DEBUG) Log.d(TAG, "started: " + config); 404c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang 405c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang heifWriter = new HeifWriter.Builder( 406c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang config.mOutputPath, width, height, config.mInputMode) 407c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang .setRotation(config.mRotation) 408c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang .setGridEnabled(config.mUseGrid) 409c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang .setMaxImages(config.mMaxNumImages) 410c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang .setQuality(config.mQuality) 411c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang .setPrimaryIndex(config.mMaxNumImages - 1) 412c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang .setHandler(config.mUseHandler ? mHandler : null) 413c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang .build(); 414c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang 415c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang if (config.mInputMode == INPUT_MODE_SURFACE) { 4167cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang mInputEglSurface = new EglWindowSurface(heifWriter.getInputSurface()); 4177cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4187cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 4197cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang heifWriter.start(); 4207cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 421c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang if (config.mInputMode == INPUT_MODE_BUFFER) { 4227cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang byte[] data = new byte[width * height * 3 / 2]; 4237cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 424c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang if (config.mInputPath != null) { 425c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang inputStream = new FileInputStream(config.mInputPath); 4267cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4277cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 4287cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (DUMP_YUV_INPUT) { 4297cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang File outputFile = new File("/sdcard/input.yuv"); 4307cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang outputFile.createNewFile(); 4317cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang outputStream = new FileOutputStream(outputFile); 4327cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4337cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 4347cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang for (int i = 0; i < numImages; i++) { 4357cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (DEBUG) Log.d(TAG, "fillYuvBuffer: " + i); 4367cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang fillYuvBuffer(i, data, width, height, inputStream); 4377cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (DUMP_YUV_INPUT) { 4387cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang Log.d(TAG, "@@@ dumping input YUV"); 4397cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang outputStream.write(data); 4407cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4417cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang heifWriter.addYuvBuffer(ImageFormat.YUV_420_888, data); 4427cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 443c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang } else if (config.mInputMode == INPUT_MODE_SURFACE) { 4447cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang // The input surface is a surface texture using single buffer mode, draws will be 4457cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang // blocked until onFrameAvailable is done with the buffer, which is dependant on 4467cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang // how fast MediaCodec processes them, which is further dependent on how fast the 4477cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang // MediaCodec callbacks are handled. We can't put draws on the same looper that 4487cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang // handles MediaCodec callback, it will cause deadlock. 4497cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang for (int i = 0; i < numImages; i++) { 4507cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (DEBUG) Log.d(TAG, "drawFrame: " + i); 4517cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang drawFrame(width, height); 4527cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4537cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang heifWriter.setInputEndOfStreamTimestamp( 4547cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1000 * computePresentationTime(numImages - 1)); 455c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang } else if (config.mInputMode == INPUT_MODE_BITMAP) { 456c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang Bitmap[] bitmaps = config.mBitmaps; 4577cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang for (int i = 0; i < Math.min(bitmaps.length, numImages); i++) { 4587cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (DEBUG) Log.d(TAG, "addBitmap: " + i); 4597cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang heifWriter.addBitmap(bitmaps[i]); 4607cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang bitmaps[i].recycle(); 4617cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4627cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4637cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 4647cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang heifWriter.stop(3000); 465c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang verifyResult(config.mOutputPath, width, height, config.mRotation, config.mUseGrid, 466c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang Math.min(numImages, config.mMaxNumImages)); 4677cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (DEBUG) Log.d(TAG, "finished: PASS"); 4687cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } finally { 4697cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang try { 4707cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (outputStream != null) { 4717cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang outputStream.close(); 4727cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4737cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (inputStream != null) { 4747cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang inputStream.close(); 4757cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4767cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } catch (IOException e) {} 4777cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 4787cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (heifWriter != null) { 4797cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang heifWriter.close(); 4807cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang heifWriter = null; 4817cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4827cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (mInputEglSurface != null) { 4837cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang // This also releases the surface from encoder. 4847cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang mInputEglSurface.release(); 4857cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang mInputEglSurface = null; 4867cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4877cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4887cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4897cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 4907cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private long computePresentationTime(int frameIndex) { 4917cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang return 132 + (long)frameIndex * 1000000; 4927cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 4937cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 4947cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private void fillYuvBuffer(int frameIndex, @NonNull byte[] data, int width, int height, 4957cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang @Nullable FileInputStream inputStream) throws IOException { 4967cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (inputStream != null) { 4977cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang inputStream.read(data); 4987cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } else { 4997cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang byte[] color = TEST_COLORS[frameIndex % TEST_COLORS.length]; 5007cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang int sizeY = width * height; 5017cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang Arrays.fill(data, 0, sizeY, color[0]); 5027cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang Arrays.fill(data, sizeY, sizeY * 5 / 4, color[1]); 5037cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang Arrays.fill(data, sizeY * 5 / 4, sizeY * 3 / 2, color[2]); 5047cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 5057cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 5067cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 5077cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private void drawFrame(int width, int height) { 5087cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang mInputEglSurface.makeCurrent(); 5097cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang generateSurfaceFrame(mInputIndex, width, height); 5107cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang mInputEglSurface.setPresentationTime(1000 * computePresentationTime(mInputIndex)); 5117cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang mInputEglSurface.swapBuffers(); 5127cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang mInputIndex++; 5137cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 5147cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 5157cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private void generateSurfaceFrame(int frameIndex, int width, int height) { 5167cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang frameIndex %= 4; 5177cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 5187cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glViewport(0, 0, width, height); 5197cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glDisable(GLES20.GL_SCISSOR_TEST); 5207cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f); 5217cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 5227cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glEnable(GLES20.GL_SCISSOR_TEST); 5237cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 5247cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang int startX, startY; 5257cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang int borderWidth = 16; 5267cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang for (int i = 0; i < 7; i++) { 5277cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang startX = (width - borderWidth * 2) * i / 7 + borderWidth; 5287cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glScissor(startX, borderWidth, 5297cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang (width - borderWidth * 2) / 7, height - borderWidth * 2); 5307cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glClearColor(((7 - i) & 0x4) * 0.16f, 5317cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang ((7 - i) & 0x2) * 0.32f, 5327cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang ((7 - i) & 0x1) * 0.64f, 5337cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 1.0f); 5347cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 5357cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 5367cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 5377cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang startX = (width / 6) + (width / 6) * frameIndex; 5387cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang startY = height / 4; 5397cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glScissor(startX, startY, width / 6, height / 3); 5407cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glClearColor(0.5f, 0.5f, 0.5f, 1.0f); 5417cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 5427cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glScissor(startX + borderWidth, startY + borderWidth, 5437cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang width / 6 - borderWidth * 2, height / 3 - borderWidth * 2); 5447cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 5457cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 5467cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 5477cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 5487cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang private void verifyResult( 549c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang String filename, int width, int height, int rotation, boolean useGrid, int numImages) 5507cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang throws Exception { 5517cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang MediaMetadataRetriever retriever = new MediaMetadataRetriever(); 5527cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang retriever.setDataSource(filename); 5537cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang String hasImage = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_HAS_IMAGE); 5547cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (!"yes".equals(hasImage)) { 5557cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang throw new Exception("No images found in file " + filename); 5567cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 5577cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang assertEquals("Wrong image count", numImages, 5587cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang Integer.parseInt(retriever.extractMetadata( 559c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang MediaMetadataRetriever.METADATA_KEY_IMAGE_COUNT))); 5607cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang assertEquals("Wrong width", width, 5617cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang Integer.parseInt(retriever.extractMetadata( 562c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang MediaMetadataRetriever.METADATA_KEY_IMAGE_WIDTH))); 5637cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang assertEquals("Wrong height", height, 5647cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang Integer.parseInt(retriever.extractMetadata( 565c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang MediaMetadataRetriever.METADATA_KEY_IMAGE_HEIGHT))); 566c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang assertEquals("Wrong rotation", rotation, 567c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang Integer.parseInt(retriever.extractMetadata( 568c6cd9ccf97400c11e449072798866f0f86b64701Chong Zhang MediaMetadataRetriever.METADATA_KEY_IMAGE_ROTATION))); 5697cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang retriever.release(); 5707cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang 5717cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang if (useGrid) { 5727cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang MediaExtractor extractor = new MediaExtractor(); 5737cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang extractor.setDataSource(filename); 5747cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang MediaFormat format = extractor.getTrackFormat(0); 575b8aa7b3a65331060158806a9a1e0e327556c6df7Jason Monk int gridWidth = format.getInteger(MediaFormat.KEY_TILE_WIDTH); 576b8aa7b3a65331060158806a9a1e0e327556c6df7Jason Monk int gridHeight = format.getInteger(MediaFormat.KEY_TILE_HEIGHT); 577b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhang int gridRows = format.getInteger(MediaFormat.KEY_GRID_ROWS); 578b8aa7b3a65331060158806a9a1e0e327556c6df7Jason Monk int gridCols = format.getInteger(MediaFormat.KEY_GRID_COLUMNS); 579b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhang assertTrue("Wrong grid width or cols", 580b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhang ((width + gridWidth - 1) / gridWidth) == gridCols); 581b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhang assertTrue("Wrong grid height or rows", 582b12f17f77f3b42d149abed231bc7875e658d08c2Chong Zhang ((height + gridHeight - 1) / gridHeight) == gridRows); 5837cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang extractor.release(); 5847cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 5857cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang } 5867cabcaccabb00c7f7068a8ebbd55eb43795eefb4Chong Zhang} 587