首页 新闻 会员 周边

app开发中采用tensorflow进行运动识别,如何将视频和识别结果一起存储为mp4?

0
悬赏园豆:100 [已解决问题] 解决于 2023-08-26 20:23

各位兄弟姐妹:
这几天一直困扰一个问题,在这里请教大家。
我在做一个安卓的app(以后可能也会迁移到IOS),采用Android Studio+tensorflow Lite进行运动识别(已经顺利完成),但是想将视频和视频上面的识别(在SurfaceView中 ,采用canvas绘制)结果导出为mp4,这个该怎么实现呢?期待朋友的指导。

A·DONG的主页 A·DONG | 初学一级 | 园豆:112
提问于:2023-04-04 20:21
< >
分享
最佳答案
0

可以使用Android中的MediaCodec和MediaMuxer类进行视频编码和混合,将每一帧的识别结果与原始帧合并,把编码后的视频帧写入输出缓冲区,再将编码后的视频帧通过MediaMuxer类的writeSampleData()方法写入新文件中

收获园豆:50
猿长大人 | 菜鸟二级 |园豆:259 | 2023-04-06 13:27
其他回答(4)
0

原本导出的文件类型是怎样的
需要写个工具或者用插件来转换

收获园豆:5
ycyzharry | 园豆:25653 (高人七级) | 2023-04-04 23:29
0

将视频和视频上的识别结果导出为 mp4 可以采用 FFmpeg 库进行处理。

FFmpeg 是一个用于处理多媒体数据的开源库,它包含了用于音视频编解码、转码、过滤等的多个工具和库,支持多种视频格式和编码方式,可在命令行中调用。

具体实现过程如下:

在 Android Studio 中添加 FFmpeg 库
可以使用以下两种方式之一:

在 build.gradle 文件中添加 FFmpeg 的依赖

groovy

implementation 'com.arthenica:mobile-ffmpeg-full-gpl:4.5.0.LTS'
将 FFmpeg 库文件放置到 Android 项目中

将 FFmpeg 库文件 libffmpeg.so 放置到 Android 项目的 app/src/main/jniLibs/ 目录下。

调用 FFmpeg 库生成 mp4 文件
使用以下命令调用 FFmpeg 库生成 mp4 文件:

shell

ffmpeg -y -f rawvideo -pixel_format argb -video_size WIDTHxHEIGHT -i - -vf "transpose=1,transpose=1,transpose=1" -c:v libx264 -preset slow -tune fastdecode -pix_fmt yuv420p -f mp4 OUTPUT.mp4
其中,rawvideo 是输入数据的格式,-pixel_format 指定像素格式,-video_size 指定视频尺寸,-i - 指定输入从标准输入读入,-vf 指定视频过滤器,-c:v 指定视频编码器,-preset 指定编码器预设,-tune 指定编码器参数,-pix_fmt 指定输出像素格式,-f mp4 指定输出格式为 mp4,最后的 OUTPUT.mp4 指定输出文件的路径和文件名。

在 Android 中调用 FFmpeg 库可以使用 ProcessBuilder 进行处理。例如:

java

ProcessBuilder pb = new ProcessBuilder(
"ffmpeg", "-y", "-f", "rawvideo", "-pixel_format", "argb",
"-video_size", "WIDTHxHEIGHT", "-i", "-", "-vf", "transpose=1,transpose=1,transpose=1",
"-c:v", "libx264", "-preset", "slow", "-tune", "fastdecode",
"-pix_fmt", "yuv420p", "-f", "mp4", "OUTPUT.mp4"
);

Process process = pb.start();

OutputStream stdin = process.getOutputStream();

// 将视频帧数据写入 stdin
// ...

stdin.flush();
stdin.close();

int ret = process.waitFor();
if (ret != 0) {
// 处理错误
}
其中,-i - 指定从标准输入读入,因此需要将视频帧数据写入 stdin 中。

收获园豆:20
Technologyforgood | 园豆:5675 (大侠五级) | 2023-04-06 19:52
0

我这边是用opencv,但是不是移动端的,而且图像识别速度没有1秒25帧,可能会卡

echo_lovely | 园豆:1437 (小虾三级) | 2023-04-07 08:58
0

要将视频和视频上面的识别结果导出为mp4格式,可以尝试进行以下步骤:

  1. 将SurfaceView中的数据绘制到Bitmap上。
    您可以在SurfaceView中使用canvas将视频和运动识别结果绘制在屏幕上。然后使用Bitmap对象将绘制的内容保存下来。可以使用以下代码将SurfaceView保存为Bitmap:
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);

其中,view是指SurfaceView对象。绘制完成后,您可以获得一个包含SurfaceView内容的Bitmap对象。

  1. 将Bitmap对象保存为视频文件。
    您可以使用视频编码库(如MediaCodec)将Bitmap对象编码为视频。代码如下:
MediaCodec mediaCodec = MediaCodec.createEncoderByType("video/avc");
MediaFormat mediaFormat = MediaFormat.createVideoFormat("video/avc", width, height);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
mediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, fps);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface);
mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, iFrameInterval);

mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
Surface surface = mediaCodec.createInputSurface();
mediaCodec.start();

MediaMuxer mediaMuxer = new MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
int trackIndex = -1;
ByteBuffer buffer = ByteBuffer.allocate(1024 * 1024);

while (true) {
    int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
    if (inputBufferIndex >= 0) {
        Bitmap bitmap = getFrame();
        if (bitmap != null) {
            Canvas canvas = surface.lockCanvas(null);
            canvas.drawBitmap(bitmap, 0, 0, null);
            surface.unlockCanvasAndPost(canvas);

            ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferIndex);
            inputBuffer.clear();
            BufferInfo bufferInfo = new BufferInfo();
            bufferInfo.presentationTimeUs = getPTSUs();
            bufferInfo.flags |= CanvasMediaCodec.BUFFER_FLAG_KEY_FRAME;
            bufferInfo.size = inputBuffer.limit();
            inputBuffer.put(buffer);
            mediaCodec.queueInputBuffer(inputBufferIndex, 0, bufferInfo.size, bufferInfo.presentationTimeUs, bufferInfo.flags);
        } else {
            mediaCodec.queueInputBuffer(inputBufferIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
        }
    }

    int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
    if (outputBufferIndex >= 0) {
        ByteBuffer outputBuffer = mediaCodec.getOutputBuffer(outputBufferIndex);
        outputBuffer.position(bufferInfo.offset);
        outputBuffer.limit(bufferInfo.offset + bufferInfo.size);
        if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0 && bufferInfo.size != 0) {
            mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
        } else {
            mediaMuxer.writeSampleData(trackIndex, outputBuffer, bufferInfo);
            mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
        }
    }

    if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
        mediaCodec.stop();
        mediaCodec.release();
        mediaMuxer.stop();
        mediaMuxer.release();
        break;
    }
}

其中,getFrame()方法可以从Bitmap对象中按照一定的时间间隔获得一帧图像,getPTSUs()方法用于记录帧时间戳,outputPath是输出的视频文件路径,widthheight是视频宽度和高度,bitRate是比特率,fps是帧率,iFrameInterval是关键帧之间的间隔。

  1. 将视频文件保存到本地。
    您可以将视频文件保存到本地。代码如下:
FileOutputStream outputStream = new FileOutputStream(outputPath);
outputStream.write(videoBytes);
outputStream.close();

其中,videoBytes是将视频编码后得到的byte数组。

以上是实现将视频和视频上面的识别结果导出为mp4的基本步骤,具体实现会因为项目的具体细节而有所差异。希望这些信息对您有所帮助!

收获园豆:25
小九九呀 | 园豆:383 (菜鸟二级) | 2023-06-17 20:26
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册