解码器初始化未能通过Chewie在Flutter上播放视频列表 [英] Decoder init failed playing a list of videos on Flutter with Chewie

查看:286
本文介绍了解码器初始化未能通过Chewie在Flutter上播放视频列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在开发Flutter应用,以顺序显示从互联网下载的视频.我正在使用Chewie组件来显示视频.

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

这是加载Chewie小部件的UI逻辑:

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());
  }
}

viewModel在哪里下载并播放媒体.

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 throws 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

视频循环播放.这意味着所有视频至少播放一次成功.由于无法在模拟器中复制视频,因此未在iOS中进行测试.

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

推荐答案

我能够解决我的错误.这有点奇怪,但是很有意义.在我的应用程序中,我正在开发TikTok之类的视频应用程序,并且正在播放和加载许多视频.目前,我的测试应用有33个视频,并且开始显示此错误.我只是将视频限制为10个,并且一切正常.由于我的应用程序主要是视频,因此,从Firestore获取视频后,便会初始化视频播放器,但无法播放.根据用户滚动,我播放视频并暂停其他视频.我认为该应用可能会加载过多的负载.但是我检查了性能图,内存使用量大约为100MB.

I was able to fix my error. It was kind of strange but make sense. In my application, I am developing a video application like TikTok and lots of videos are playing and loading. Currently, my testing app has 33 videos and it starts to show this error. I just limit the video limit to 10 and everything works fine. Since my application is mainly videos, once I got the videos from firestore, I initialized the video players but not playing. Depend on the user scroll I play the videos and pause others. I think may be too much load for the app. But I check the performance graphs and memory usage is around 100MB.

这篇关于解码器初始化未能通过Chewie在Flutter上播放视频列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆