1 /* 2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.media.benchmark.tests; 17 18 import com.android.media.benchmark.R; 19 import com.android.media.benchmark.library.Extractor; 20 import com.android.media.benchmark.library.Muxer; 21 import com.android.media.benchmark.library.Native; 22 import com.android.media.benchmark.library.Stats; 23 24 import androidx.test.platform.app.InstrumentationRegistry; 25 26 import android.content.Context; 27 import android.media.MediaCodec; 28 import android.media.MediaFormat; 29 import android.media.MediaMuxer; 30 import android.util.Log; 31 32 import org.junit.BeforeClass; 33 import org.junit.Test; 34 import org.junit.runner.RunWith; 35 import org.junit.runners.Parameterized; 36 37 import java.io.File; 38 import java.io.FileDescriptor; 39 import java.io.FileInputStream; 40 import java.io.FileOutputStream; 41 import java.io.IOException; 42 import java.nio.ByteBuffer; 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.Collection; 46 import java.util.Hashtable; 47 import java.util.Map; 48 49 import static org.junit.Assert.assertTrue; 50 import static org.junit.Assert.assertEquals; 51 import static org.junit.Assert.assertNotEquals; 52 53 import static org.junit.Assert.assertTrue; 54 55 @RunWith(Parameterized.class) 56 public class MuxerTest { 57 private static Context mContext = 58 InstrumentationRegistry.getInstrumentation().getTargetContext(); 59 private static final String mInputFilePath = mContext.getString(R.string.input_file_path); 60 private static final String mStatsFile = 61 mContext.getExternalFilesDir(null) + "/Muxer." + System.currentTimeMillis() + ".csv"; 62 private static final String TAG = "MuxerTest"; 63 private static final Map<String, Integer> mMapFormat = new Hashtable<String, Integer>() { 64 { 65 put("mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); 66 put("webm", MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM); 67 put("3gpp", MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP); 68 put("ogg", MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG); 69 } 70 }; 71 private String mInputFileName; 72 private String mFormat; 73 74 @Parameterized.Parameters inputFiles()75 public static Collection<Object[]> inputFiles() { 76 return Arrays.asList(new Object[][]{ 77 /* Parameters: filename, format */ 78 {"crowd_1920x1080_25fps_4000kbps_vp8.webm", "webm"}, 79 {"crowd_1920x1080_25fps_4000kbps_vp9.webm", "webm"}, 80 {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "mp4"}, 81 {"crowd_352x288_25fps_6000kbps_h263.3gp", "mp4"}, 82 {"crowd_1920x1080_25fps_6700kbps_h264.ts", "mp4"}, 83 {"crowd_1920x1080_25fps_4000kbps_h265.mkv", "mp4"}, 84 {"crowd_1920x1080_25fps_6000kbps_mpeg4.mp4", "3gpp"}, 85 {"crowd_352x288_25fps_6000kbps_h263.3gp", "3gpp"}, 86 {"crowd_1920x1080_25fps_6700kbps_h264.ts", "3gpp"}, 87 {"crowd_1920x1080_25fps_4000kbps_h265.mkv", "3gpp"}, 88 {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", "ogg"}, 89 {"bbb_44100hz_2ch_80kbps_vorbis_5mins.webm", "webm"}, 90 {"bbb_48000hz_2ch_100kbps_opus_5mins.webm", "webm"}, 91 {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "mp4"}, 92 {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "mp4"}, 93 {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "mp4"}, 94 {"bbb_44100hz_2ch_128kbps_aac_5mins.mp4", "3gpp"}, 95 {"bbb_8000hz_1ch_8kbps_amrnb_5mins.3gp", "3gpp"}, 96 {"bbb_16000hz_1ch_9kbps_amrwb_5mins.3gp", "3gpp"}}); 97 } 98 MuxerTest(String filename, String outputFormat)99 public MuxerTest(String filename, String outputFormat) { 100 this.mInputFileName = filename; 101 this.mFormat = outputFormat; 102 } 103 104 @BeforeClass writeStatsHeaderToFile()105 public static void writeStatsHeaderToFile() throws IOException { 106 Stats mStats = new Stats(); 107 boolean status = mStats.writeStatsHeader(mStatsFile); 108 assertTrue("Unable to open stats file for writing!", status); 109 Log.d(TAG, "Saving Benchmark results in: " + mStatsFile); 110 } 111 112 @Test testMuxer()113 public void testMuxer() throws IOException { 114 File inputFile = new File(mInputFilePath + mInputFileName); 115 assertTrue("Cannot find " + mInputFileName + " in directory " + mInputFilePath, 116 inputFile.exists()); 117 FileInputStream fileInput = new FileInputStream(inputFile); 118 FileDescriptor fileDescriptor = fileInput.getFD(); 119 ArrayList<ByteBuffer> inputBuffer = new ArrayList<>(); 120 ArrayList<MediaCodec.BufferInfo> inputBufferInfo = new ArrayList<>(); 121 Extractor extractor = new Extractor(); 122 int trackCount = extractor.setUpExtractor(fileDescriptor); 123 for (int currentTrack = 0; currentTrack < trackCount; currentTrack++) { 124 extractor.selectExtractorTrack(currentTrack); 125 while (true) { 126 int sampleSize = extractor.getFrameSample(); 127 MediaCodec.BufferInfo bufferInfo = extractor.getBufferInfo(); 128 MediaCodec.BufferInfo tempBufferInfo = new MediaCodec.BufferInfo(); 129 tempBufferInfo 130 .set(bufferInfo.offset, bufferInfo.size, bufferInfo.presentationTimeUs, 131 bufferInfo.flags); 132 inputBufferInfo.add(tempBufferInfo); 133 ByteBuffer tempSampleBuffer = ByteBuffer.allocate(tempBufferInfo.size); 134 tempSampleBuffer.put(extractor.getFrameBuffer().array(), 0, bufferInfo.size); 135 inputBuffer.add(tempSampleBuffer); 136 if (sampleSize < 0) { 137 break; 138 } 139 } 140 MediaFormat format = extractor.getFormat(currentTrack); 141 int outputFormat = mMapFormat.getOrDefault(mFormat, -1); 142 assertNotEquals("Test failed for " + mInputFileName + ". Returned invalid " + 143 "output format for given " + mFormat + " format.", -1, outputFormat); 144 Muxer muxer = new Muxer(); 145 int trackIndex = muxer.setUpMuxer(mContext, outputFormat, format); 146 int status = muxer.mux(trackIndex, inputBuffer, inputBufferInfo); 147 assertEquals("Cannot perform write operation for " + mInputFileName, 0, status); 148 Log.i(TAG, "Muxed " + mInputFileName + " successfully."); 149 muxer.deInitMuxer(); 150 muxer.dumpStatistics(mInputFileName, mFormat, extractor.getClipDuration(), mStatsFile); 151 muxer.resetMuxer(); 152 extractor.unselectExtractorTrack(currentTrack); 153 inputBufferInfo.clear(); 154 inputBuffer.clear(); 155 156 } 157 extractor.deinitExtractor(); 158 fileInput.close(); 159 } 160 161 @Test testNativeMuxer()162 public void testNativeMuxer() { 163 Native nativeMuxer = new Native(); 164 File inputFile = new File(mInputFilePath + mInputFileName); 165 assertTrue("Cannot find " + mInputFileName + " in directory " + mInputFilePath, 166 inputFile.exists()); 167 int tid = android.os.Process.myTid(); 168 String mMuxOutputFile = (mContext.getFilesDir() + "/mux_" + tid + ".out"); 169 int status = nativeMuxer.Mux( 170 mInputFilePath, mInputFileName, mMuxOutputFile, mStatsFile, mFormat); 171 assertEquals("Cannot perform write operation for " + mInputFileName, 0, status); 172 Log.i(TAG, "Muxed " + mInputFileName + " successfully."); 173 File muxedFile = new File(mMuxOutputFile); 174 // Cleanup temporary output file 175 if (muxedFile.exists()) { 176 assertTrue("Unable to delete" + mMuxOutputFile + " file.", 177 muxedFile.delete()); 178 } 179 } 180 } 181