flutter下载m3u8视频

m3u8是苹果公司推出的视频播放标准,是m3u的一种,只是编码格式采用的是UTF-8。
存储的信息类似于:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:6
#EXTINF:5,
abc_0123.ts
#EXTINF:5,
abc_0124.ts
#EXTINF:5,
abc_0125.ts
#EXT-X-ENDLIST

m3u8准确来说是一种索引文件,使用m3u8文件实际上是通过它来解析对应的放在服务器上的视频网络地址,从而实现在线播放。
在flutter中,要下载m3u8的视频,实际上是要将m3u8中列出的abc_0123.ts视频文件全部下载下来,再合成一个mp4文件。
需要用到几个插件

flutter_hls_parser: ^2.0.0  // 解析m3u8文件
ffmpeg_kit_flutter: 4.5.1-LTS  // 合成mp4文件
image_gallery_saver: ^1.7.1  // 保存到手机相册

具体代码如下

import "dart:io";

import "package:bot_toast/bot_toast.dart";
import "package:dio/dio.dart";
import "package:ffmpeg_kit_flutter/ffmpeg_kit.dart";
import "package:ffmpeg_kit_flutter/ffmpeg_session.dart";
import "package:ffmpeg_kit_flutter/log.dart";
import "package:ffmpeg_kit_flutter/statistics.dart";
import "package:flutter/material.dart";
import "package:flutter_hls_parser/flutter_hls_parser.dart";
import "package:image_gallery_saver/image_gallery_saver.dart";
import "package:path_provider/path_provider.dart";

class DownloadM3U8Util {
  DownloadM3U8Util._();

  static final DownloadM3U8Util instance = DownloadM3U8Util._();
  List downLoadUrl = [];

  // 传入m3u8下载地址
  Future downloadM3u8(String url) async {
    debugPrint("DownloadUtil, _url=$url");
    if (downLoadUrl.contains(url)) {
      print("已进入下载队列");
      return;
    }
    final String savePath = await _getSavePath();  // 存储路径
   
    downLoadUrl.add(url);
    final String host = url.substring(0, url.lastIndexOf("/"));
    final String m3u8FileName = url.substring(url.lastIndexOf("/") + 1); // m3u8文件名带后缀.  xxx.m3u8
    final String m3u8Path = "$savePath/$m3u8FileName"; // m3u8保存绝对路径  /abc/../xxx.m3u8
    final String m3u8Name = m3u8FileName.split(".").first; // m3u8文件名不带后缀  xxx

    final Response response = await Dio().download(url, m3u8Path);
    if (response.statusCode != 200) {
      print("下载 m3u8 失败 _url=$url");
      downLoadUrl.remove(url);
      return;
    }
    // video文件夹不存在则创建
    Directory directory = Directory("$savePath/video/");
    if (!directory.existsSync()) {
      directory.createSync();
    }

    HlsPlaylist playList;
    try {
      playList = await HlsPlaylistParser.create()
          .parse(Uri.parse(url), await File(m3u8Path).readAsLines());
    } on ParserException catch (e) {
      print(e);
    }

    if (playList is HlsMediaPlaylist) {
      // 读取m3u8文件的URL信息
      final mediaPlaylistUrls = playList.segments.map((it) => it.url);
      for (var value in mediaPlaylistUrls) {
        // value  oux02488.ts
        String tsUrl = "$host/$value";
        File file = File("$savePath/$value");
        if (!file.existsSync()) {
          file.create();
        }
        print("下载ts地址 url=$tsUrl, file.path=${file.path}");
        Response _response = await Dio().download(tsUrl, file.path);
        if (_response.statusCode != 200) {
          downLoadUrl.remove(url);
          return;
        }
      }
      print("已下载完所有ts视频");
      String cmd = '-allowed_extensions ALL -i $m3u8Path  "$savePath/video/$m3u8Name.mp4"';

      ///合并ts为mp4
      FFmpegKit.executeAsync(cmd, (FFmpegSession session) {
        BotToast.showText(text: "下载成功");
        downLoadUrl.remove(url);
        // 保存到相册
        ImageGallerySaver.saveFile("$savePath/video/$m3u8Name.mp4").then((value) {
          // 删除临时路径的文件
          File file = File("$savePath/video/$m3u8Name.mp4");
          file.deleteSync();
        });
      });
    }
  }

  /// 获取存储路径
  static Future _getSavePath() async {
    final directory = Platform.isAndroid
        ? await getExternalStorageDirectory()
        : await getApplicationDocumentsDirectory();
    return directory.path;
  }
}

你可能感兴趣的:(flutter下载m3u8视频)