xref: /aosp_15_r20/cts/tests/media/src/android/mediav2/cts/MuxerUnitTest.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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 
17 package android.mediav2.cts;
18 
19 import static android.system.Os.pipe;
20 
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 
24 import android.media.MediaCodec;
25 import android.media.MediaFormat;
26 import android.media.MediaMuxer;
27 
28 import androidx.test.filters.SmallTest;
29 
30 import com.android.compatibility.common.util.ApiTest;
31 import com.android.compatibility.common.util.FrameworkSpecificTest;
32 
33 import org.junit.After;
34 import org.junit.Before;
35 import org.junit.Ignore;
36 import org.junit.Rule;
37 import org.junit.Test;
38 import org.junit.experimental.runners.Enclosed;
39 import org.junit.rules.TestName;
40 import org.junit.runner.RunWith;
41 
42 import java.io.File;
43 import java.io.FileDescriptor;
44 import java.io.FileInputStream;
45 import java.io.IOException;
46 import java.nio.ByteBuffer;
47 import java.nio.charset.StandardCharsets;
48 
49 /**
50  * Tests MediaMuxer API that are independent of MediaMuxer.OutputFormat. Constructors,
51  * addTrack, start, writeSampleData, stop, release are independent of OutputFormat selected.
52  * Legality of these APIs are tested in this class.
53  */
54 @RunWith(Enclosed.class)
55 public class MuxerUnitTest {
56     // duplicate definitions of hide fields of MediaMuxer.OutputFormat.
57     private static final int MUXER_OUTPUT_LAST = MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG;
58 
59     @FrameworkSpecificTest
60     @SmallTest
61     public static class TestApi {
62         @Rule
63         public TestName testName = new TestName();
64 
65         @Before
prologue()66         public void prologue() throws IOException {
67             mOutMedia = File.createTempFile(testName.getMethodName(), ".out");
68             mOutLoc = mOutMedia.getAbsolutePath();
69         }
70 
71         @After
epilogue()72         public void epilogue() {
73             new File(mOutLoc).delete();
74         }
75 
76         private File mOutMedia;
77         private String mOutLoc;
78 
79         // Insert one frame SubRip
insertPerFrameSubtitles(MediaMuxer muxer, long presentationTimeUs, int trackID)80         static private void insertPerFrameSubtitles(MediaMuxer muxer, long presentationTimeUs,
81                 int trackID) {
82             byte[] greeting = "hello world".getBytes(StandardCharsets.UTF_8);
83             ByteBuffer metaBuff = ByteBuffer.allocate(greeting.length);
84             metaBuff.put(greeting);
85             MediaCodec.BufferInfo metaInfo = new MediaCodec.BufferInfo();
86             metaInfo.offset = 0;
87             metaInfo.size = greeting.length;
88             metaInfo.presentationTimeUs = presentationTimeUs;
89             metaInfo.flags = 0;
90             muxer.writeSampleData(trackID, metaBuff, metaInfo);
91         }
92 
93         @ApiTest(apis = "android.media.MediaMuxer#MediaMuxer")
94         @Test
testIfNullPathIsRejected()95         public void testIfNullPathIsRejected() {
96             MediaMuxer muxer = null;
97             try {
98                 String nullPath = null;
99                 muxer = new MediaMuxer(nullPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
100                 fail("null destination path accepted by constructor");
101             } catch (IllegalArgumentException e) {
102                 // expected
103             } catch (Exception e) {
104                 fail(e.getMessage());
105             } finally {
106                 if (null != muxer) muxer.release();
107             }
108         }
109 
110         @ApiTest(apis = "android.media.MediaMuxer#MediaMuxer")
111         @Test
testIfNullFdIsRejected()112         public void testIfNullFdIsRejected() {
113             MediaMuxer muxer = null;
114             try {
115                 FileDescriptor fd = null;
116                 muxer = new MediaMuxer(fd, MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
117                 fail("null fd accepted by constructor");
118             } catch (IllegalArgumentException e) {
119                 // expected
120             } catch (Exception e) {
121                 fail(e.getMessage());
122             } finally {
123                 if (null != muxer) muxer.release();
124             }
125         }
126 
127         @ApiTest(apis = "android.media.MediaMuxer#MediaMuxer")
128         @Test
testIfInvalidFdIsRejected()129         public void testIfInvalidFdIsRejected() {
130             MediaMuxer muxer = null;
131             try {
132                 FileDescriptor fd = new FileDescriptor();
133                 muxer = new MediaMuxer(fd, MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
134                 fail("Invalid fd accepted by constructor");
135             } catch (IllegalArgumentException e) {
136                 // expected
137             } catch (Exception e) {
138                 fail(e.getMessage());
139             } finally {
140                 if (null != muxer) muxer.release();
141             }
142         }
143 
144         @ApiTest(apis = "android.media.MediaMuxer#MediaMuxer")
145         @Test
testIfReadOnlyFdIsRejected()146         public void testIfReadOnlyFdIsRejected() {
147             MediaMuxer muxer = null;
148             try (FileInputStream fInp = new FileInputStream(mOutMedia)) {
149                 muxer = new MediaMuxer(fInp.getFD(), MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
150                 fail("fd with read-only attribute accepted by constructor");
151             } catch (IOException e) {
152                 // expected
153             } catch (Exception e) {
154                 fail(e.getMessage());
155             } finally {
156                 if (null != muxer) muxer.release();
157             }
158         }
159 
160         @ApiTest(apis = "android.media.MediaMuxer#MediaMuxer")
161         @Test
testIfNonSeekableFdIsRejected()162         public void testIfNonSeekableFdIsRejected() {
163             MediaMuxer muxer = null;
164             try {
165                 FileDescriptor[] fd = pipe();
166                 muxer = new MediaMuxer(fd[1], MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
167                 fail("pipe, a non-seekable fd accepted by constructor");
168             } catch (IllegalArgumentException e) {
169                 // expected
170             } catch (Exception e) {
171                 fail(e.getMessage());
172             } finally {
173                 if (null != muxer) muxer.release();
174             }
175         }
176 
177         @ApiTest(apis = "android.media.MediaMuxer#MediaMuxer")
178         @Test
testIfInvalidOutputFormatIsRejected()179         public void testIfInvalidOutputFormatIsRejected() {
180             MediaMuxer muxer = null;
181             try {
182                 muxer = new MediaMuxer(mOutLoc, MUXER_OUTPUT_LAST + 1);
183                 fail("Invalid Media format accepted by constructor");
184             } catch (IllegalArgumentException e) {
185                 // expected
186             } catch (Exception e) {
187                 fail(e.getMessage());
188             } finally {
189                 if (null != muxer) muxer.release();
190             }
191         }
192 
193         @ApiTest(apis = "android.media.MediaMuxer#addTrack")
194         @Test
testIfNullMediaFormatIsRejected()195         public void testIfNullMediaFormatIsRejected() throws IOException {
196             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
197             try {
198                 muxer.addTrack(null);
199                 fail("null media format accepted by addTrack");
200             } catch (IllegalArgumentException e) {
201                 // expected
202             } finally {
203                 muxer.release();
204             }
205         }
206 
207         @ApiTest(apis = "android.media.MediaMuxer#addTrack")
208         @Test
testIfInvalidMediaFormatIsRejected()209         public void testIfInvalidMediaFormatIsRejected() throws IOException {
210             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
211             try {
212                 // Invalid media format - no mediaType key
213                 try {
214                     muxer.addTrack(new MediaFormat());
215                     fail("Invalid media format accepted by addTrack");
216                 } catch (IllegalArgumentException e) {
217                     // expected
218                 }
219 
220                 // metadata mediaType format shall start with "application/*"
221                 try {
222                     MediaFormat format = new MediaFormat();
223                     format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_CEA_608);
224                     muxer.addTrack(format);
225                     fail("Invalid media format accepted by addTrack");
226                 } catch (IllegalArgumentException | IllegalStateException e) {
227                     // Ideally check only for IllegalArgumentException.
228                     // expected
229                 }
230             } finally {
231                 muxer.release();
232             }
233         }
234 
235         @ApiTest(apis = "android.media.MediaMuxer#addTrack")
236         @Test
testIfCorruptMediaFormatIsRejected()237         public void testIfCorruptMediaFormatIsRejected() throws IOException {
238             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
239 
240              /* TODO(b/278260304): Audio/Video formats, have certain keys required to be set. It
241                 is noticed that even when these keys are not set, no exceptions were raised. Do we
242                 need to add fixtures for those cases. */
243             try {
244                 MediaFormat format = new MediaFormat();
245                 format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_AAC);
246                 format.setInteger(MediaFormat.KEY_SAMPLE_RATE, -1);
247                 muxer.addTrack(format);
248                 muxer.start();
249                 fail("muxer accepts media format with required key-value pairs missing");
250             } catch (Exception e) {
251                 // expected
252             } finally {
253                 muxer.release();
254             }
255         }
256 
257         @ApiTest(apis = "android.media.MediaMuxer#addTrack")
258         @Test
testIfAddTrackSucceedsAfterStart()259         public void testIfAddTrackSucceedsAfterStart() throws IOException {
260             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
261             try {
262                 MediaFormat format = new MediaFormat();
263                 format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
264                 muxer.addTrack(format);
265                 muxer.start();
266                 muxer.addTrack(format);
267                 fail("muxer.addTrack() succeeded after muxer.start()");
268             } catch (IllegalStateException e) {
269                 // expected
270             } catch (Exception e) {
271                 fail(e.getMessage());
272             } finally {
273                 muxer.release();
274             }
275         }
276 
277         @ApiTest(apis = "android.media.MediaMuxer#addTrack")
278         @Test
testIfAddTrackSucceedsAfterWriteSampleData()279         public void testIfAddTrackSucceedsAfterWriteSampleData() throws IOException {
280             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
281             try {
282                 MediaFormat format = new MediaFormat();
283                 format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
284                 int trackID = muxer.addTrack(format);
285                 muxer.start();
286                 insertPerFrameSubtitles(muxer, 0, trackID);
287                 muxer.addTrack(format);
288                 fail("muxer.addTrack() succeeded after muxer.writeSampleData()");
289             } catch (IllegalStateException e) {
290                 // expected
291             } catch (Exception e) {
292                 fail(e.getMessage());
293             } finally {
294                 muxer.release();
295             }
296         }
297 
298         @ApiTest(apis = "android.media.MediaMuxer#addTrack")
299         @Test
testIfAddTrackSucceedsAfterStop()300         public void testIfAddTrackSucceedsAfterStop() throws IOException {
301             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
302             try {
303                 MediaFormat format = new MediaFormat();
304                 format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
305                 int trackID = muxer.addTrack(format);
306                 muxer.start();
307                 insertPerFrameSubtitles(muxer, 0, trackID);
308                 muxer.stop();
309                 muxer.addTrack(format);
310                 fail("muxer.addTrack() succeeded after muxer.stop()");
311             } catch (IllegalStateException e) {
312                 // expected
313             } catch (Exception e) {
314                 fail(e.getMessage());
315             } finally {
316                 muxer.release();
317             }
318         }
319 
320         @ApiTest(apis = "android.media.MediaMuxer#addTrack")
321         @Test
testIfAddTrackSucceedsAfterRelease()322         public void testIfAddTrackSucceedsAfterRelease() throws IOException {
323             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
324             try {
325                 MediaFormat format = new MediaFormat();
326                 format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
327                 muxer.release();
328                 muxer.addTrack(format);
329                 fail("muxer.addTrack() succeeded after muxer.release()");
330             } catch (IllegalStateException e) {
331                 // expected
332             } catch (Exception e) {
333                 fail(e.getMessage());
334             } finally {
335                 muxer.release();
336             }
337         }
338 
339         @ApiTest(apis = "android.media.MediaMuxer#start")
340         @Test
testIfMuxerStartsBeforeAddTrack()341         public void testIfMuxerStartsBeforeAddTrack() throws IOException {
342             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
343             MediaFormat format = new MediaFormat();
344             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
345 
346             try {
347                 muxer.start();
348                 fail("muxer.start() succeeded before muxer.addTrack()");
349             } catch (IllegalStateException e) {
350                 // expected
351             } catch (Exception e) {
352                 fail(e.getMessage());
353             } finally {
354                 muxer.release();
355             }
356         }
357 
358         @ApiTest(apis = "android.media.MediaMuxer#start")
359         @Test
testIdempotentStart()360         public void testIdempotentStart() throws IOException {
361             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
362             MediaFormat format = new MediaFormat();
363             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
364 
365             try {
366                 muxer.addTrack(format);
367                 muxer.start();
368                 muxer.start();
369                 fail("muxer.start() succeeded after muxer.start()");
370             } catch (IllegalStateException e) {
371                 // expected
372             } catch (Exception e) {
373                 fail(e.getMessage());
374             } finally {
375                 muxer.release();
376             }
377         }
378 
379         @ApiTest(apis = "android.media.MediaMuxer#start")
380         @Test
testIfMuxerStartsAfterWriteSampleData()381         public void testIfMuxerStartsAfterWriteSampleData() throws IOException {
382             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
383             MediaFormat format = new MediaFormat();
384             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
385 
386             try {
387                 int trackID = muxer.addTrack(format);
388                 muxer.start();
389                 insertPerFrameSubtitles(muxer, 0, trackID);
390                 muxer.start();
391                 fail("muxer.start() succeeded after muxer.writeSampleData()");
392             } catch (IllegalStateException e) {
393                 // expected
394             } catch (Exception e) {
395                 fail(e.getMessage());
396             } finally {
397                 muxer.release();
398             }
399         }
400 
401         @ApiTest(apis = "android.media.MediaMuxer#start")
402         @Test
testIfMuxerStartsAfterStop()403         public void testIfMuxerStartsAfterStop() throws IOException {
404             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
405             MediaFormat format = new MediaFormat();
406             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
407 
408             try {
409                 int trackID = muxer.addTrack(format);
410                 muxer.start();
411                 insertPerFrameSubtitles(muxer, 0, trackID);
412                 muxer.stop();
413                 muxer.start();
414                 fail("muxer.start() succeeded after muxer.stop()");
415             } catch (IllegalStateException e) {
416                 // expected
417             } catch (Exception e) {
418                 fail(e.getMessage());
419             } finally {
420                 muxer.release();
421             }
422         }
423 
424         @ApiTest(apis = "android.media.MediaMuxer#start")
425         @Test
testIfMuxerStartsAfterRelease()426         public void testIfMuxerStartsAfterRelease() throws IOException {
427             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
428 
429             try {
430                 muxer.release();
431                 muxer.start();
432                 fail("muxer.start() succeeded after muxer.release()");
433             } catch (IllegalStateException e) {
434                 // expected
435             } catch (Exception e) {
436                 fail(e.getMessage());
437             } finally {
438                 muxer.release();
439             }
440         }
441 
442         @ApiTest(apis = "android.media.MediaMuxer#stop")
443         @Test
testStopOnANonStartedMuxer()444         public void testStopOnANonStartedMuxer() throws IOException {
445             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
446 
447             try {
448                 muxer.stop();
449                 fail("muxer.stop() succeeded before muxer.start()");
450             } catch (IllegalStateException e) {
451                 // expected
452             } catch (Exception e) {
453                 fail(e.getMessage());
454             } finally {
455                 muxer.release();
456             }
457         }
458 
459         @ApiTest(apis = "android.media.MediaMuxer#stop")
460         @Test
testIdempotentStop()461         public void testIdempotentStop() throws IOException {
462             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
463             MediaFormat format = new MediaFormat();
464             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
465 
466             try {
467                 int trackID = muxer.addTrack(format);
468                 muxer.start();
469                 insertPerFrameSubtitles(muxer, 0, trackID);
470                 muxer.stop();
471                 muxer.stop();
472                 fail("muxer.stop() succeeded after muxer.stop()");
473             } catch (IllegalStateException e) {
474                 // expected
475             } catch (Exception e) {
476                 fail(e.getMessage());
477             } finally {
478                 muxer.release();
479             }
480         }
481 
482         @ApiTest(apis = "android.media.MediaMuxer#stop")
483         @Test
testStopAfterRelease()484         public void testStopAfterRelease() throws IOException {
485             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
486             try {
487                 muxer.release();
488                 muxer.stop();
489                 fail("muxer.stop() succeeded after muxer.release()");
490             } catch (IllegalStateException e) {
491                 // expected
492             } catch (Exception e) {
493                 fail(e.getMessage());
494             } finally {
495                 muxer.release();
496             }
497         }
498 
499         @ApiTest(apis = {"android.media.MediaMuxer#start", "android.media.MediaMuxer#stop"})
500         @Test
testSimpleStartStopMuxer()501         public void testSimpleStartStopMuxer() throws IOException {
502             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
503             MediaFormat format = new MediaFormat();
504             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
505 
506             try {
507                 muxer.addTrack(format);
508                 muxer.start();
509                 muxer.stop();
510             } catch (Exception e) {
511                 fail(e.getMessage());
512             } finally {
513                 muxer.release();
514             }
515         }
516 
517         @ApiTest(apis = "android.media.MediaMuxer#writeSampleData")
518         @Test
testIfWriteSampleDataRejectsInvalidTrackIndex()519         public void testIfWriteSampleDataRejectsInvalidTrackIndex() throws IOException {
520             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
521             MediaFormat format = new MediaFormat();
522             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
523 
524             int trackID = muxer.addTrack(format);
525             muxer.start();
526             insertPerFrameSubtitles(muxer, 22000, trackID);
527             try {
528                 insertPerFrameSubtitles(muxer, 0, trackID - 1);
529                 fail("muxer.writeSampleData() succeeded with bad argument, trackIndex");
530             } catch (IllegalArgumentException e) {
531                 // expected
532             } finally {
533                 muxer.release();
534             }
535         }
536 
537         @ApiTest(apis = "android.media.MediaMuxer#writeSampleData")
538         @Test
testIfWriteSampleDataRejectsNullByteBuffer()539         public void testIfWriteSampleDataRejectsNullByteBuffer() throws IOException {
540             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
541             MediaFormat format = new MediaFormat();
542             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
543 
544             int trackID = muxer.addTrack(format);
545             muxer.start();
546             insertPerFrameSubtitles(muxer, 22000, trackID);
547 
548             MediaCodec.BufferInfo metaInfo = new MediaCodec.BufferInfo();
549             metaInfo.offset = 0;
550             metaInfo.size = 24;
551             metaInfo.presentationTimeUs = 0;
552             metaInfo.flags = 0;
553             try {
554                 muxer.writeSampleData(trackID, null, metaInfo);
555                 fail("muxer.writeSampleData() succeeded with bad argument, byteBuffer = null");
556             } catch (IllegalArgumentException e) {
557                 // expected
558             } finally {
559                 muxer.release();
560             }
561         }
562 
563         @ApiTest(apis = "android.media.MediaMuxer#writeSampleData")
564         @Test
testIfWriteSampleDataRejectsNullBuffInfo()565         public void testIfWriteSampleDataRejectsNullBuffInfo() throws IOException {
566             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
567             MediaFormat format = new MediaFormat();
568             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
569 
570             int trackID = muxer.addTrack(format);
571             muxer.start();
572             insertPerFrameSubtitles(muxer, 22000, trackID);
573 
574             byte[] greeting = "hello world".getBytes(StandardCharsets.UTF_8);
575             ByteBuffer metaBuff = ByteBuffer.allocate(greeting.length);
576             metaBuff.put(greeting);
577 
578             try {
579                 muxer.writeSampleData(trackID, metaBuff, null);
580                 fail("muxer.writeSampleData() succeeded with bad argument, byteBuffer = null");
581             } catch (IllegalArgumentException e) {
582                 // expected
583             } finally {
584                 muxer.release();
585             }
586         }
587 
588         @ApiTest(apis = "android.media.MediaMuxer#writeSampleData")
589         @Test
testIfWriteSampleDataRejectsInvalidBuffInfo()590         public void testIfWriteSampleDataRejectsInvalidBuffInfo() throws IOException {
591             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
592             MediaFormat format = new MediaFormat();
593             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
594 
595             int trackID = muxer.addTrack(format);
596             muxer.start();
597             insertPerFrameSubtitles(muxer, 22000, trackID);
598 
599             byte[] greeting = "hello world".getBytes(StandardCharsets.UTF_8);
600             ByteBuffer metaBuff = ByteBuffer.allocate(greeting.length);
601             metaBuff.put(greeting);
602 
603             MediaCodec.BufferInfo metaInfo = new MediaCodec.BufferInfo();
604 
605             try {
606                 // invalid metaData : buffer offset < 0
607                 try {
608                     metaInfo.offset = -1;
609                     metaInfo.size = greeting.length;
610                     metaInfo.presentationTimeUs = 0;
611                     metaInfo.flags = 0;
612                     muxer.writeSampleData(trackID, metaBuff, metaInfo);
613                     fail("muxer.writeSampleData() succeeded with bad argument, bufInfo.offset < 0");
614                 } catch (IllegalArgumentException e) {
615                     // expected
616                 }
617 
618                 // invalid metaData : buffer size < 0
619                 try {
620                     metaInfo.offset = 0;
621                     metaInfo.size = -1;
622                     metaInfo.presentationTimeUs = 0;
623                     metaInfo.flags = 0;
624                     muxer.writeSampleData(trackID, metaBuff, metaInfo);
625                     fail("muxer.writeSampleData() succeeded with bad argument, buffInfo.size < 0");
626                 } catch (IllegalArgumentException e) {
627                     // expected
628                 }
629 
630                 // invalid metaData : buffer size > capacity
631                 try {
632                     metaInfo.offset = 0;
633                     metaInfo.size = greeting.length * 2;
634                     metaInfo.presentationTimeUs = 0;
635                     metaInfo.flags = 0;
636                     muxer.writeSampleData(trackID, metaBuff, metaInfo);
637                     fail("muxer.writeSampleData() succeeded with bad argument, buffInfo.size > " +
638                             "byteBuffer.capacity()");
639                 } catch (IllegalArgumentException e) {
640                     // expected
641                 }
642 
643                 // invalid metaData : buffer offset + size > capacity
644                 try {
645                     metaInfo.offset = 1;
646                     metaInfo.size = greeting.length;
647                     metaInfo.presentationTimeUs = 0;
648                     metaInfo.flags = 0;
649                     muxer.writeSampleData(trackID, metaBuff, metaInfo);
650                     fail("muxer.writeSampleData() succeeded with bad argument, bufferInfo.offset " +
651                             "+ bufferInfo.size > byteBuffer.capacity()");
652                 } catch (IllegalArgumentException e) {
653                     // expected
654                 }
655             } finally {
656                 muxer.release();
657             }
658         }
659 
660         @ApiTest(apis = "android.media.MediaMuxer#writeSampleData")
661         @Test
662         @Ignore("TODO(b/147128377)")
testIfWriteSampleDataRejectsInvalidPts()663         public void testIfWriteSampleDataRejectsInvalidPts() throws IOException {
664             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
665             MediaFormat format = new MediaFormat();
666             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
667 
668             int trackID = muxer.addTrack(format);
669             muxer.start();
670             insertPerFrameSubtitles(muxer, 22000, trackID);
671             try {
672                 insertPerFrameSubtitles(muxer, -33000, trackID);
673                 fail("muxer.writeSampleData() succeeded with bad argument, presentationTime");
674             } catch (IllegalArgumentException e) {
675                 // expected
676             } finally {
677                 muxer.release();
678             }
679         }
680 
681         @ApiTest(apis = "android.media.MediaMuxer#writeSampleData")
682         @Test
testIfWriteSampleDataSucceedsBeforeStart()683         public void testIfWriteSampleDataSucceedsBeforeStart() throws IOException {
684             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
685             MediaFormat format = new MediaFormat();
686             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
687 
688             try {
689                 int trackID = muxer.addTrack(format);
690                 insertPerFrameSubtitles(muxer, 0, trackID);
691                 fail("muxer.WriteSampleData() succeeds before muxer.start()");
692             } catch (IllegalStateException e) {
693                 // expected
694             } catch (Exception e) {
695                 fail(e.getMessage());
696             } finally {
697                 muxer.release();
698             }
699         }
700 
701         @ApiTest(apis = "android.media.MediaMuxer#writeSampleData")
702         @Test
testIfWriteSampleDataSucceedsAfterStop()703         public void testIfWriteSampleDataSucceedsAfterStop() throws IOException {
704             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
705             MediaFormat format = new MediaFormat();
706             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
707 
708             try {
709                 int trackID = muxer.addTrack(format);
710                 muxer.start();
711                 insertPerFrameSubtitles(muxer, 0, trackID);
712                 muxer.stop();
713                 insertPerFrameSubtitles(muxer, 0, trackID);
714                 fail("muxer.WriteSampleData() succeeds after muxer.stop()");
715             } catch (IllegalStateException e) {
716                 // expected
717             } catch (Exception e) {
718                 fail(e.getMessage());
719             } finally {
720                 muxer.release();
721             }
722         }
723 
724         @ApiTest(apis = "android.media.MediaMuxer#writeSampleData")
725         @Test
testIfWriteSampleDataSucceedsAfterRelease()726         public void testIfWriteSampleDataSucceedsAfterRelease() throws IOException {
727             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
728             MediaFormat format = new MediaFormat();
729             format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_TEXT_SUBRIP);
730 
731             try {
732                 int trackID = muxer.addTrack(format);
733                 muxer.start();
734                 insertPerFrameSubtitles(muxer, 0, trackID);
735                 muxer.release();
736                 insertPerFrameSubtitles(muxer, 0, trackID);
737                 fail("muxer.WriteSampleData() succeeds after muxer.release()");
738             } catch (IllegalStateException e) {
739                 // expected
740             } catch (Exception e) {
741                 fail(e.getMessage());
742             } finally {
743                 muxer.release();
744             }
745         }
746 
747         @ApiTest(apis = "android.media.MediaMuxer#release")
748         @Test
testIdempotentRelease()749         public void testIdempotentRelease() throws IOException {
750             MediaMuxer muxer = new MediaMuxer(mOutLoc, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
751             try {
752                 muxer.release();
753                 muxer.release();
754             } catch (Exception e) {
755                 fail(e.getMessage());
756             }
757         }
758     }
759 
760     @FrameworkSpecificTest
761     @SmallTest
762     public static class TestApiNative {
763         @Rule
764         public TestName testName = new TestName();
765 
766         static {
767             System.loadLibrary("ctsmediav2muxer_jni");
768         }
769 
770         @Before
prologue()771         public void prologue() throws IOException {
772             File mOutMedia = File.createTempFile(testName.getMethodName(), ".out");
773             mOutLoc = mOutMedia.getAbsolutePath();
774         }
775 
776         @After
epilogue()777         public void epilogue() {
778             new File(mOutLoc).delete();
779         }
780 
781         private String mOutLoc;
782 
nativeTestIfInvalidFdIsRejected()783         private native boolean nativeTestIfInvalidFdIsRejected();
nativeTestIfReadOnlyFdIsRejected(String outPath)784         private native boolean nativeTestIfReadOnlyFdIsRejected(String outPath);
nativeTestIfNonSeekableFdIsRejected()785         private native boolean nativeTestIfNonSeekableFdIsRejected();
nativeTestIfInvalidOutputFormatIsRejected(String outPath)786         private native boolean nativeTestIfInvalidOutputFormatIsRejected(String outPath);
787 
nativeTestIfInvalidMediaFormatIsRejected(String outPath)788         private native boolean nativeTestIfInvalidMediaFormatIsRejected(String outPath);
nativeTestIfCorruptMediaFormatIsRejected(String outPath)789         private native boolean nativeTestIfCorruptMediaFormatIsRejected(String outPath);
nativeTestIfAddTrackSucceedsAfterStart(String outPath)790         private native boolean nativeTestIfAddTrackSucceedsAfterStart(String outPath);
nativeTestIfAddTrackSucceedsAfterWriteSampleData(String outPath)791         private native boolean nativeTestIfAddTrackSucceedsAfterWriteSampleData(String outPath);
nativeTestIfAddTrackSucceedsAfterStop(String outPath)792         private native boolean nativeTestIfAddTrackSucceedsAfterStop(String outPath);
793 
nativeTestIfMuxerStartsBeforeAddTrack(String outPath)794         private native boolean nativeTestIfMuxerStartsBeforeAddTrack(String outPath);
nativeTestIdempotentStart(String outPath)795         private native boolean nativeTestIdempotentStart(String outPath);
nativeTestIfMuxerStartsAfterWriteSampleData(String outPath)796         private native boolean nativeTestIfMuxerStartsAfterWriteSampleData(String outPath);
nativeTestIfMuxerStartsAfterStop(String outPath)797         private native boolean nativeTestIfMuxerStartsAfterStop(String outPath);
798 
nativeTestStopOnANonStartedMuxer(String outPath)799         private native boolean nativeTestStopOnANonStartedMuxer(String outPath);
nativeTestIdempotentStop(String outPath)800         private native boolean nativeTestIdempotentStop(String outPath);
nativeTestSimpleStartStop(String outPath)801         private native boolean nativeTestSimpleStartStop(String outPath);
802 
nativeTestIfWriteSampleDataRejectsInvalidTrackIndex(String outPath)803         private native boolean nativeTestIfWriteSampleDataRejectsInvalidTrackIndex(String outPath);
nativeTestIfWriteSampleDataRejectsInvalidPts(String outPath)804         private native boolean nativeTestIfWriteSampleDataRejectsInvalidPts(String outPath);
nativeTestIfWriteSampleDataSucceedsBeforeStart(String outPath)805         private native boolean nativeTestIfWriteSampleDataSucceedsBeforeStart(String outPath);
nativeTestIfWriteSampleDataSucceedsAfterStop(String outPath)806         private native boolean nativeTestIfWriteSampleDataSucceedsAfterStop(String outPath);
807 
808         @ApiTest(apis = "AMediaMuxer_new")
809         @Test
testIfInvalidFdIsRejected()810         public void testIfInvalidFdIsRejected() {
811             assertTrue(nativeTestIfInvalidFdIsRejected());
812         }
813 
814         @ApiTest(apis = "AMediaMuxer_new")
815         @Test
testIfReadOnlyFdIsRejected()816         public void testIfReadOnlyFdIsRejected() {
817             assertTrue(nativeTestIfReadOnlyFdIsRejected(mOutLoc));
818         }
819 
820         @ApiTest(apis = "AMediaMuxer_new")
821         @Test
testIfNonSeekableFdIsRejected()822         public void testIfNonSeekableFdIsRejected() {
823             assertTrue(nativeTestIfNonSeekableFdIsRejected());
824         }
825 
826         @ApiTest(apis = "AMediaMuxer_new")
827         @Test
testIfInvalidOutputFormatIsRejected()828         public void testIfInvalidOutputFormatIsRejected() {
829             assertTrue(nativeTestIfInvalidOutputFormatIsRejected(mOutLoc));
830         }
831 
832         @ApiTest(apis = "AMediaMuxer_addTrack")
833         @Test
testIfInvalidMediaFormatIsRejected()834         public void testIfInvalidMediaFormatIsRejected() {
835             assertTrue(nativeTestIfInvalidMediaFormatIsRejected(mOutLoc));
836         }
837 
838         @ApiTest(apis = "AMediaMuxer_addTrack")
839         @Test
testIfCorruptMediaFormatIsRejected()840         public void testIfCorruptMediaFormatIsRejected() {
841             assertTrue(nativeTestIfCorruptMediaFormatIsRejected(mOutLoc));
842         }
843 
844         @ApiTest(apis = "AMediaMuxer_addTrack")
845         @Test
testIfAddTrackSucceedsAfterStart()846         public void testIfAddTrackSucceedsAfterStart() {
847             assertTrue(nativeTestIfAddTrackSucceedsAfterStart(mOutLoc));
848         }
849 
850         @ApiTest(apis = "AMediaMuxer_addTrack")
851         @Test
testIfAddTrackSucceedsAfterWriteSampleData()852         public void testIfAddTrackSucceedsAfterWriteSampleData() {
853             assertTrue(nativeTestIfAddTrackSucceedsAfterWriteSampleData(mOutLoc));
854         }
855 
856         @ApiTest(apis = "AMediaMuxer_addTrack")
857         @Test
testIfAddTrackSucceedsAfterStop()858         public void testIfAddTrackSucceedsAfterStop() {
859             assertTrue(nativeTestIfAddTrackSucceedsAfterStop(mOutLoc));
860         }
861 
862         @ApiTest(apis = "AMediaMuxer_start")
863         @Test
testIfMuxerStartsBeforeAddTrack()864         public void testIfMuxerStartsBeforeAddTrack() {
865             assertTrue(nativeTestIfMuxerStartsBeforeAddTrack(mOutLoc));
866         }
867 
868         @ApiTest(apis = "AMediaMuxer_start")
869         @Test
testIdempotentStart()870         public void testIdempotentStart() {
871             assertTrue(nativeTestIdempotentStart(mOutLoc));
872         }
873 
874         @ApiTest(apis = "AMediaMuxer_start")
875         @Test
testIfMuxerStartsAfterWriteSampleData()876         public void testIfMuxerStartsAfterWriteSampleData() {
877             assertTrue(nativeTestIfMuxerStartsAfterWriteSampleData(mOutLoc));
878         }
879 
880         @ApiTest(apis = "AMediaMuxer_start")
881         @Test
testIfMuxerStartsAfterStop()882         public void testIfMuxerStartsAfterStop() {
883             assertTrue(nativeTestIfMuxerStartsAfterStop(mOutLoc));
884         }
885 
886         @ApiTest(apis = "AMediaMuxer_stop")
887         @Test
testStopOnANonStartedMuxer()888         public void testStopOnANonStartedMuxer() {
889             assertTrue(nativeTestStopOnANonStartedMuxer(mOutLoc));
890         }
891 
892         @ApiTest(apis = "AMediaMuxer_stop")
893         @Test
testIdempotentStop()894         public void testIdempotentStop() {
895             assertTrue(nativeTestIdempotentStop(mOutLoc));
896         }
897 
898         @ApiTest(apis = {"AMediaMuxer_start", "AMediaMuxer_stop"})
899         @Test
testSimpleStartStopMuxer()900         public void testSimpleStartStopMuxer() {
901             assertTrue(nativeTestSimpleStartStop(mOutLoc));
902         }
903 
904         @ApiTest(apis = "AMediaMuxer_writeSampleData")
905         @Test
testIfWriteSampleDataRejectsInvalidTrackIndex()906         public void testIfWriteSampleDataRejectsInvalidTrackIndex() {
907             assertTrue(nativeTestIfWriteSampleDataRejectsInvalidTrackIndex(mOutLoc));
908         }
909 
910         @ApiTest(apis = "AMediaMuxer_writeSampleData")
911         @Test
912         @Ignore("TODO(b/147128377)")
testIfWriteSampleDataRejectsInvalidPts()913         public void testIfWriteSampleDataRejectsInvalidPts() {
914             assertTrue(nativeTestIfWriteSampleDataRejectsInvalidPts(mOutLoc));
915         }
916 
917         @ApiTest(apis = "AMediaMuxer_writeSampleData")
918         @Test
testIfWriteSampleDataSucceedsBeforeStart()919         public void testIfWriteSampleDataSucceedsBeforeStart() {
920             assertTrue(nativeTestIfWriteSampleDataSucceedsBeforeStart(mOutLoc));
921         }
922 
923         @ApiTest(apis = "AMediaMuxer_writeSampleData")
924         @Test
testIfWriteSampleDataSucceedsAfterStop()925         public void testIfWriteSampleDataSucceedsAfterStop() {
926             assertTrue(nativeTestIfWriteSampleDataSucceedsAfterStop(mOutLoc));
927         }
928     }
929 }
930