Flutter如何保存(重新编码)文本叠加在视频上

13
我希望实现类似Instagram故事的功能(只有文本叠加)。 我已经能够让用户像下面截图中所示那样在视频上添加一些文本(右上角的图标开始输入文本,左上角返回上一页)。 用户输入一些文本后,我想将视频存储到Firebase存储中。 但问题是如何将这个文本保留在视频中? 是否有一种方法可以重新编码具有用户添加文本叠加的文件? 还是必须将文本信息存储到数据库中,然后每次获取并显示?

enter image description here


1
你所说的简单方法是将文本存储在Firestore中,并在需要时获取,否则您将需要使用本地代码来操作视频。 - diegoveloper
谢谢您的评论。好的,我会这样做,但有一件事让我担心,那就是设备尺寸彼此不同。例如,用户A从iPhone X输入文本,而用户B从iPhone SE观看视频,由于SE比X小得多,因此用户A可能将文本放在底部,用户B可能无法看到它,我是对的吗?我该如何使其响应?您有什么想法吗? - Daibaku
1
使用LayoutBuilder检查我的答案:https://dev59.com/L63la4cB1Zd3GeqPOo0m#51796799 - diegoveloper
谢谢,我会检查一下。另外,Flutter是否支持重新编码视频的功能? - Daibaku
1
使用平台通道应该是可能的。 - diegoveloper
@Daibaku 你得到了这个问题的解决方案吗?因为我想做同样的事情,但没有找到任何解决方案。请帮帮我。 谢谢! - Alpit Panchal
3个回答

3
也许不是完整的答案,我相信您需要自己努力才能让它工作。
所以,我面临一个类似的情况,需要向录制的视频添加一些覆盖层。
我发现了这个软件包https://github.com/tanersener/flutter-ffmpeg
如果您了解有关ffmpeg的一些信息,您会发现它包括一些视频和音频处理工具。
我还没有尝试过,但很快就会开始并向您更新任何方法。如果可能的话,我可能会为其编写一个软件包,以便可以轻松地将叠加层添加到视频中。
如果您发现其他内容,请告诉我。

嗨,@Jose Tapizquent,我也想使用Flutter在视频上添加文本水印。你找到了任何方法吗?请告诉我。谢谢。 - tyb9900
@Jose Tapizquent,我正在处理视频的水印和文字,你有任何结果吗? - Ryan Wang
你能否使用这个包给视频添加水印? - Dennis Ashford

3

2
我只能给出部分答案,希望它能有所帮助。 在Flutter中,您可以使用PictureRecorderCanvas导出为位图或png格式。 生成的png图像应与源视频具有相同的大小,并且可以通过简单的Image小部件覆盖在视频上。 您还可以将此png图像上传到Firebase,然后在其他客户端下载它,以获得完全相同的外观(即使未安装字体)。 令人惊奇的是,您甚至可以在png图像中保存手绘图、贴纸、渐变和复杂形状(您可以在画布上绘制的所有内容)。 如果需要,您也可以使用某种本地库将png图像添加到视频中。 以下是一个简单的示例,展示如何生成和显示这样的png图像:
import 'dart:async';
import 'dart:typed_data';
import 'dart:ui' as ui;

import 'package:flutter/material.dart';

/// @param size Video size
/// @param text Styled text
ui.Image createTextImage(Size size, TextSpan text) {
  final recorder = ui.PictureRecorder();
  final cullRect = Offset.zero & size;
  final canvas = Canvas(recorder, cullRect);

  final textPainter = TextPainter(textDirection: TextDirection.ltr, text: text);
  textPainter.layout();

  // draw text in center of canvas, you can adjust this as you like
  final textOffset = cullRect.center.translate(-textPainter.width / 2, textPainter.height / 2);
  textPainter.paint(canvas, textOffset);

  // you can also draw other geometrical shapes, gradients, paths...
  canvas.drawCircle(Offset(100.0, 100.0), 50.0, Paint()..color = Color(0xffff00ff));

  final picture = recorder.endRecording();
  final image = picture.toImage(size.width.toInt(), size.height.toInt());

  return image;
}

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Canvas Test',
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => new _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  /// Bytes of the generated image
  Future<Uint8List> _imageBytes;

  _generateImage() {
    // Get this size from your video
    final videoSize = Size(720.0, 1280.0);

    final textStyle = TextStyle(
      fontFamily: 'Roboto',
      fontSize: 80.0,
      color: Colors.red,
    );
    final text = TextSpan(text: 'Hello World', style: textStyle);

    // Generate the image
    final imageInfo = createTextImage(videoSize, text);

    // Convert to png
    final imageBytes =
        imageInfo.toByteData(format: ui.ImageByteFormat.png).then((byteData) => Uint8List.view(byteData.buffer));

    setState(() {
      _imageBytes = imageBytes;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Canvas Test'),
      ),
      body: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: <Widget>[
            FutureBuilder(
              future: _imageBytes,
              builder: (BuildContext context, AsyncSnapshot<Uint8List> snapshot) {
                if (!snapshot.hasData) return Text('No data');

                // Display the generated image in a box
                return DecoratedBox(
                  decoration: BoxDecoration(border: Border.all()),
                  child: Image.memory(
                    snapshot.data,
                    width: 180.0,
                    height: 320.0,
                  ),
                );
              },
            ),
            RaisedButton(onPressed: _generateImage, child: Text('Generate Image'))
          ],
        ),
      ),
    );
  }
}

谢谢你的好回答,但我觉得我没有正确理解。你说的是关于图像的吗?如果我想要编码视频,我也必须编写本地代码吗? - Daibaku
很有可能。Dart没有视频操作库。您考虑过使用后端服务进行视频操作吗? - boformer
现在我明白了,谢谢boformer。不,我没有,你有什么推荐吗?我的计划是让用户捕捉视频,然后将其存储到Firebase中。 - Daibaku
看一下这个问题:https://stackoverflow.com/questions/37854506/how-to-add-a-watermark-to-a-video-in-android-java - boformer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接