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