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