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