Decoder init failed playing a list of videos on Flutter with Chewie

余生颓废 提交于 2020-04-30 08:48:38

问题


I'm developing a Flutter app to show sequentially videos downloaded from internet. I'm using the Chewie component to show the videos.

This is the UI logic to load the Chewie Widget:

class SliderScreen extends StatefulWidget {
  static String id = 'SliderScreen';

  @override
  _SliderScreenState createState() => _SliderScreenState();
}

class _SliderScreenState extends State<SliderScreen> {
  SliderViewModel vModel;

  @override
  void initState() {
    super.initState();
  }

  @override
  void dispose() {
    if (null != vModel) vModel.dispose();

    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return BaseView<SliderViewModel>(
        onModelReady: (model) {
          model.downloadController = locator<DownloadController>();
          model.downloadController.init(callback: model.onFirstFileDownloaded);

          vModel = model;

          vModel.getSlots(isFirstCall: true);
        },
        builder: (context, model, child) => null != model.medias && model.medias.length > 0
            ? FutureBuilder(
                future: model.initializeVideoPlayerFuture,
                builder: (context, snapshot) {
                  if (snapshot.connectionState == ConnectionState.done) {
                    vModel.chewieController.play();

                    return AspectRatio(
                        aspectRatio: 16 / 9,
                        // Use the VideoPlayer widget to display the video.
                        child: Center(
                          child: null != vModel.chewieController ? Chewie(controller: vModel.chewieController) : Center(child: CircularProgressIndicator()),
                        ));
                  } else {
                    return SizedBox(
                      height: 300,
                      child: Center(child: CircularProgressIndicator()),
                    );
                  }
                })
            : SizedBox());
  }
}

And the viewModel where is the download and play the medias.

class SliderViewModel extends BaseViewModel {
  static String id = 'SliderViewModel';
  static int kFiveMinutes = 5 * 60;

  Slot currentSlot;
  Slot nextSlot;

  DownloadController downloadController;
  Timer nextSlotTimer;

  List<TaskInfo> medias = [];

  VideoPlayerController videoController;
  ChewieController chewieController;

  bool _disposed = false;
  var _isPlaying = false;
  var _isEndPlaying = false;
  var _canPlay = true;
  String token;
  int currentIndex = 0;

  Future<void> initializeVideoPlayerFuture;

  void getSlots({bool isFirstCall = false}) async {
    //get videos to show.....
  }

  void addToDownload({Slot slot, bool resetMedias = false}) async {
    if (resetMedias) {
      medias.clear();

      downloadController.clearTasks();
      await downloadController.cancelDownload();
    }

    await downloadController.addMediasToDownload(ads: slot.ads, slotStart: slot.slot.sta);
    downloadController.startDownloadMedias();
  }

  Future<void> _startPlay() async {
    print("play ---------> ${medias[currentIndex].path}");
    initializeVideoPlayerFuture = null;

    Future.delayed(const Duration(milliseconds: 200), () {
      _clearPrevious().then((_) {
        _initializePlay();
      });
    });
  }

  Future<void> _initializePlay() async {
    print('*****************      preparing ${medias[currentIndex].path}');

    videoController = VideoPlayerController.file(File(medias[currentIndex].path));

    videoController.addListener(_controllerListener);

    chewieController = ChewieController(
      videoPlayerController: videoController,
      aspectRatio: 16 / 9,
      fullScreenByDefault: true,
      showControls: true,
      autoPlay: true,
      // Prepare the video to be played and display the first frame
      autoInitialize: true,
      looping: false,
      // Errors can occur for example when trying to play a video
      // from a non-existent URL
      errorBuilder: (context, errorMessage) {
        return Center(
          child: Text(
            errorMessage,
            style: TextStyle(color: Colors.white),
          ),
        );
      },
    );
    //chewieController.addListener(_controllerListener);

    initializeVideoPlayerFuture = videoController.initialize();
    setState(ViewState.Idle);
  }

  Future<bool> _clearPrevious() async {
    await videoController?.pause();
    videoController?.removeListener(_controllerListener);
    await videoController?.dispose();
    return true;
  }

  void onFirstFileDownloaded(TaskInfo task) {
    if (null != task) {
      print('current slot: ${currentSlot.slot.sta} - task slot: ${task.slotStart} - ${task.name} FINISH!!!');

      if (currentSlot.slot.sta == task.slotStart) {
        medias.add(task);

        if (!_isPlaying) {
          if (_canPlay) {
            loadNextMedia();

            _canPlay = false;
          }
        }
      }
    } else
      print('all files downloaded!!!');
  }

  Future<void> _controllerListener() async {
    if (videoController == null || _disposed) {
      return;
    }
    if (!videoController.value.initialized) {
      return;
    }
    final position = await videoController.position;
    final duration = videoController.value.duration;
    final isPlaying = position.inMilliseconds < duration.inMilliseconds;
    final isEndPlaying = position.inMilliseconds > 0 && position.inSeconds == duration.inSeconds;

    if (_isPlaying != isPlaying || _isEndPlaying != isEndPlaying) {
      _isPlaying = isPlaying;
      _isEndPlaying = isEndPlaying;

      print(" -----> isPlaying=$isPlaying");
      if (!_isPlaying) {
        //mark media as viewed
        print('send viewed ${medias[currentIndex].ad.id}');
        apiServices.sendViewed(
            token: token,
            adId: medias[currentIndex].ad.id.toString(),
            userId: await AppSingleton().storage.read(key: kUserId),
            slotId: currentSlot.slot.tsi.toString(),
            def: medias[currentIndex].ad.def.toString());

        final isComplete = medias.length - 1 == currentIndex;

        if (isComplete) {
          print("played all!!");

          if (currentSlot.slot.loop == 0 || currentSlot.slot.loop == 1 && medias[currentIndex].ad.def == 0) medias.removeAt(currentIndex);

          currentIndex = 0;

          if (currentSlot.slot.loop == 1) loadNextMedia();

          setState(ViewState.Idle);
        } else {
          _canPlay = true;

          print('finish play ${medias[currentIndex].name} - slot: ${medias[currentIndex].slotStart}');

          if (currentSlot.slot.loop == 0 || (currentSlot.slot.loop == 1 && medias[currentIndex].ad.def == 0))
            medias.removeAt(currentIndex);
          else
            currentIndex++;

          if (medias.length > currentIndex)
            loadNextMedia();
          else
            setState(ViewState.Idle);
        }
      }
    }
  }

  void loadNextMedia() {
      _startPlay();
  }

  @override
  void dispose() {
    _disposed = true;
    videoController.dispose();
    chewieController.dispose();
    initializeVideoPlayerFuture = null;
    super.dispose();
  }
}

Works fine at the beginning, but after some videos are displayed, the app thorws the exception.

Playback error.
E/ExoPlayerImplInternal(12983): com.google.android.exoplayer2.ExoPlaybackException: com.google.android.exoplayer2.mediacodec.MediaCodecRenderer$DecoderInitializationException: Decoder init failed: OMX.qcom.video.decoder.avc, Format(1, null, null, video/avc, null, -1, null, [1280, 720, -1.0], [-1, -1])
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodec(MediaCodecRenderer.java:479)
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.reinitializeCodec(MediaCodecRenderer.java:1261)
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.onInputFormatChanged(MediaCodecRenderer.java:1111)
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.onInputFormatChanged(MediaCodecVideoRenderer.java:552)
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:647)
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:529)
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:300)
E/ExoPlayerImplInternal(12983):     at android.os.Handler.dispatchMessage(Handler.java:102)
E/ExoPlayerImplInternal(12983):     at android.os.Looper.loop(Looper.java:193)
E/ExoPlayerImplInternal(12983):     at android.os.HandlerThread.run(HandlerThread.java:65)
E/ExoPlayerImplInternal(12983): Caused by: com.google.android.exoplayer2.mediacodec.MediaCodecRenderer$DecoderInitializationException: Decoder init failed: OMX.qcom.video.decoder.avc, Format(1, null, null, video/avc, null, -1, null, [1280, 720, -1.0], [-1, -1])
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.initCodecWithFallback(MediaCodecRenderer.java:753)
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodec(MediaCodecRenderer.java:474)
E/ExoPlayerImplInternal(12983):     ... 9 more
E/ExoPlayerImplInternal(12983): Caused by: android.media.MediaCodec$CodecException: Failed to initialize OMX.qcom.video.decoder.avc, error 0xfffffff4
E/ExoPlayerImplInternal(12983):     at android.media.MediaCodec.native_setup(Native Method)
E/ExoPlayerImplInternal(12983):     at android.media.MediaCodec.<init>(MediaCodec.java:1811)
E/ExoPlayerImplInternal(12983):     at android.media.MediaCodec.createByCodecName(MediaCodec.java:1792)
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.initCodec(MediaCodecRenderer.java:802)
E/ExoPlayerImplInternal(12983):     at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.initCodecWithFallback(MediaCodecRenderer.java:745)
E/ExoPlayerImplInternal(12983):     ... 10 more

The videos are played in loop. That means all videos are played at least one time succesful. In iOS has not tested because can't reproduce videos in simulators.

Thanks in advance.

来源:https://stackoverflow.com/questions/60883887/decoder-init-failed-playing-a-list-of-videos-on-flutter-with-chewie

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!