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