【问题标题】:Flutter how to save(re-encode) text overlay on videoFlutter 如何在视频上保存(重新编码)文本覆盖
【发布时间】:2019-01-21 23:24:00
【问题描述】:

我想实现类似 instagram 故事的功能(仅限文本叠加)。 我能够达到用户可以在视频上添加一些文本的地步,如下面的屏幕截图(右上角的图标开始输入文本,左上角只是回到上一页)。 用户输入一些文本后,我想将视频存储到Firebase storage。 但问题是我怎样才能在视频中保留这段文字? 有没有办法重写具有文本覆盖用户放置的文件(重新编码)? 还是我必须将文本信息存储到数据库中,然后每次都获取并显示?

【问题讨论】:

  • 您所说的简单方法是将文本存储在firestore中并在需要时获取,否则您将需要使用本机代码来操作视频。
  • 感谢您的评论。好的,我会这样做,但我担心的一件事是设备尺寸彼此不同。比如userA从Iphone x放文字,userB从Iphone SE看视频,userA把文字放在最下面,因为SE比X小很多,userB可能看不到对吗?我怎样才能让它响应?你有什么想法吗?
  • 使用 LayoutBuilder 在这里查看我的答案:stackoverflow.com/questions/51786364/…
  • 谢谢,我会检查的。另外,Flutter 有没有可能支持对视频的重新编码?
  • 使用平台渠道应该是可以的

标签: flutter overlay encode


【解决方案1】:

也许不是一个完整的答案,因为我相信你必须自己做一些工作才能让它发挥作用。

所以,我面临着类似的情况,我需要在录制的视频中添加一些叠加内容。

我遇到了这个包https://github.com/tanersener/flutter-ffmpeg

如果您查看一些有关 ffmpeg 的信息,您会发现它包含一些视频和音频处理工具。

我还没有尝试过,但我很快就会开始并用任何方法更新你。 如果可能的话,我可能会为其编写一个包,以便可以轻松地将叠加层添加到视频中。

如果你有其他发现,请告诉我

【讨论】:

  • 嗨@Jose Tapizquent 我还想使用颤振在视频上添加文本水印。你找到什么方法了吗?请告诉我。谢谢
  • @Jose Tapizquent,我正在处理视频的水印和文字,你有结果吗?
【解决方案2】:

我只能给出部分答案,希望对你有所帮助。

您可以使用PictureRecorder 在 Flutter 中导出Canvas 的位图或 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'))
          ],
        ),
      ),
    );
  }
}

【讨论】:

  • 感谢您的出色回答,但我认为我的理解不正确。你说的是图像吗?如果我想编码视频,我也必须编写原生代码?
  • 很有可能。 dart 没有视频处理库。您是否考虑过使用后端服务来处理视频?
  • 现在我明白了,谢谢 boformer。不,我没有,你有什么推荐的吗?我的计划是让用户捕获视频,然后将其存储到 firebase。
【解决方案3】:

有一家酒吧 (https://pub.dev/packages/tapioca),但功能非常有限。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-12
    • 1970-01-01
    • 2019-08-06
    • 1970-01-01
    相关资源
    最近更新 更多