Bug 1350279 - try other codecs when first one failed to create. r=esawin a=gchang
authorJohn Lin <jolin@mozilla.com>
Mon, 29 May 2017 11:40:49 +0200
changeset 396431 c4c3049f649ed4b79466f1c3bb62f4871aa619e7
parent 396430 1e504e2b22218ea1dabdae39d4b17c870389551b
child 396432 e62e4db3e31d37fc93c4b3b99f450eba48d78a6a
push id1468
push userasasaki@mozilla.com
push dateMon, 05 Jun 2017 19:31:07 +0000
treeherdermozilla-release@0641fc6ee9d1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersesawin, gchang
bugs1350279
milestone54.0
Bug 1350279 - try other codecs when first one failed to create. r=esawin a=gchang Video fails to play on Sony Z3C when the media server is in a state that no hardware codec can be created unless reboot. Fallback to software codec when that happens to workaround the issue. MozReview-Commit-ID: AaRIw7KPaF3
mobile/android/base/java/org/mozilla/gecko/media/Codec.java
--- a/mobile/android/base/java/org/mozilla/gecko/media/Codec.java
+++ b/mobile/android/base/java/org/mozilla/gecko/media/Codec.java
@@ -316,16 +316,17 @@ import java.util.concurrent.ConcurrentLi
             if (mStopped) {
                 return;
             }
             mStopped = true;
             reset();
         }
     }
 
+    private String mName;
     private volatile ICodecCallbacks mCallbacks;
     private AsyncCodec mCodec;
     private InputProcessor mInputProcessor;
     private OutputProcessor mOutputProcessor;
     private SamplePool mSamplePool;
     // Value will be updated after configure called.
     private volatile boolean mIsAdaptivePlaybackSupported = false;
 
@@ -357,26 +358,19 @@ import java.util.concurrent.ConcurrentLi
 
         if (mCodec != null) {
             if (DEBUG) { Log.d(LOGTAG, "release existing codec: " + mCodec); }
             releaseCodec();
         }
 
         if (DEBUG) { Log.d(LOGTAG, "configure " + this); }
 
-        MediaFormat fmt = format.asFormat();
-        String codecName = getDecoderForFormat(fmt);
-        if (codecName == null) {
-            Log.e(LOGTAG, "FAIL: cannot find codec");
-            return false;
-        }
-
         try {
-            AsyncCodec codec = AsyncCodecFactory.create(codecName);
-
+            MediaFormat fmt = format.asFormat();
+            AsyncCodec codec = createCodecForFormat(fmt);
             MediaCrypto crypto = RemoteMediaDrmBridgeStub.getMediaCrypto(drmStubId);
             if (DEBUG) {
                 boolean hasCrypto = crypto != null;
                 Log.d(LOGTAG, "configure mediacodec with crypto(" + hasCrypto + ") / Id :" + drmStubId);
             }
 
             codec.setCallbacks(new Callbacks(), null);
 
@@ -392,22 +386,21 @@ import java.util.concurrent.ConcurrentLi
                     fmt.setInteger(MediaFormat.KEY_MAX_HEIGHT, 1080);
                 }
             }
 
             codec.configure(fmt, surface, crypto, flags);
             mCodec = codec;
             mInputProcessor = new InputProcessor();
             mOutputProcessor = new OutputProcessor(renderToSurface);
-            mSamplePool = new SamplePool(codecName, renderToSurface);
+            mSamplePool = new SamplePool(mName, renderToSurface);
             if (DEBUG) { Log.d(LOGTAG, codec.toString() + " created. Render to surface?" + renderToSurface); }
             return true;
         } catch (Exception e) {
-            Log.e(LOGTAG, "FAIL: cannot create codec -- " + codecName);
-            e.printStackTrace();
+            Log.e(LOGTAG, "codec creation error", e);
             return false;
         }
     }
 
     @Override
     public synchronized boolean isAdaptivePlaybackSupported() {
         return mIsAdaptivePlaybackSupported;
     }
@@ -420,38 +413,43 @@ import java.util.concurrent.ConcurrentLi
 
             mCodec.release();
         } catch (Exception e) {
             reportError(Error.FATAL, e);
         }
         mCodec = null;
     }
 
-    private String getDecoderForFormat(MediaFormat format) {
+    private AsyncCodec createCodecForFormat(MediaFormat format) throws IOException {
         String mime = format.getString(MediaFormat.KEY_MIME);
-        if (mime == null) {
-            return null;
+        if (mime == null || mime.isEmpty()) {
+            throw new IllegalArgumentException("invalid MIME type: " + mime);
         }
+
         int numCodecs = MediaCodecList.getCodecCount();
         for (int i = 0; i < numCodecs; i++) {
             MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
             if (info.isEncoder()) {
                 continue;
             }
             String[] types = info.getSupportedTypes();
             for (String t : types) {
-                if (t.equalsIgnoreCase(mime)) {
-                    return info.getName();
+                if (!t.equalsIgnoreCase(mime)) {
+                    continue;
+                }
+                try {
+                    AsyncCodec codec = AsyncCodecFactory.create(info.getName());
+                    mName = info.getName();
+                    return codec;
+                } catch (IllegalArgumentException e) {
+                    Log.w(LOGTAG, "unable to create " + info.getName() + ". Try next codec.");
                 }
             }
         }
-        return null;
-        // TODO: API 21+ is simpler.
-        //static MediaCodecList sCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
-        //return sCodecList.findDecoderForFormat(format);
+        throw new RuntimeException("cannot create codec for " + mime);
     }
 
     @Override
     public synchronized void start() throws RemoteException {
         if (DEBUG) { Log.d(LOGTAG, "start " + this); }
         mInputProcessor.start();
         mOutputProcessor.start();
         try {