【问题标题】:Compress Videos using FFMPEG and JNI使用 FFMPEG 和 JNI 压缩视频
【发布时间】:2013-12-29 03:01:44
【问题描述】:

我想创建一个 android 应用程序,它可以定位视频文件(超过 300 mb)并将其压缩为较小的 mp4 文件。

我已经尝试过使用this

本教程非常有效,因为您正在压缩小尺寸视频(小于 100 mb)

所以我尝试使用 JNI 来实现它。

我设法使用 this 构建 ffmpeg

但目前我想做的是压缩视频。我对JNI没有很好的了解。但我尝试使用以下 link

来理解它

如果有人可以指导我使用 JNI 打开文件后压缩视频的步骤,那真是太棒了,谢谢

【问题讨论】:

  • 你说教程对小尺寸视频很有效。那么大视频也照着做有什么问题吗?
  • @AndroSelva 是的,实际上是面向设备的

标签: android ffmpeg java-native-interface android-videoview


【解决方案1】:

假设您已经获得了输入文件的字符串路径,我们可以相当轻松地完成您的任务。我假设您了解 NDK 基础知识:如何将本机 .c 文件连接到相应 .java 文件中的 native 方法(如果这是您问题的一部分,请告诉我)。相反,我将专注于如何在 Android / JNI 的上下文中使用 FFmpeg。

高级概述:

#include <jni.h>
#include <android/log.h>
#include <string.h>
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"

#define LOG_TAG "FFmpegWrapper"
#define LOGI(...)  __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)


void Java_com_example_yourapp_yourJavaClass_compressFile(JNIEnv *env, jobject obj, jstring jInputPath, jstring jInputFormat, jstring jOutputPath, jstring JOutputFormat){
  // One-time FFmpeg initialization
  av_register_all();
  avformat_network_init();
  avcodec_register_all();

  const char* inputPath = (*env)->GetStringUTFChars(env, jInputPath, NULL);
  const char* outputPath = (*env)->GetStringUTFChars(env, jOutputPath, NULL);
  // format names are hints. See available options on your host machine via $ ffmpeg -formats
  const char* inputFormat = (*env)->GetStringUTFChars(env, jInputFormat, NULL);
  const char* outputFormat = (*env)->GetStringUTFChars(env, jOutputFormat, NULL);

  AVFormatContext *outputFormatContext = avFormatContextForOutputPath(outputPath, outputFormat);
  AVFormatContext *inputFormatContext = avFormatContextForInputPath(inputPath, inputFormat /* not necessary since file can be inspected */);

  copyAVFormatContext(&outputFormatContext, &inputFormatContext);
  // Modify outputFormatContext->codec parameters per your liking
  // See http://ffmpeg.org/doxygen/trunk/structAVCodecContext.html

  int result = openFileForWriting(outputFormatContext, outputPath);
  if(result < 0){
      LOGE("openFileForWriting error: %d", result);
  }

  writeFileHeader(outputFormatContext);

  // Copy input to output frame by frame
  AVPacket *inputPacket;
  inputPacket = av_malloc(sizeof(AVPacket));

  int continueRecording = 1;
  int avReadResult = 0;
  int writeFrameResult = 0;
  int frameCount = 0;
  while(continueRecording == 1){
      avReadResult = av_read_frame(inputFormatContext, inputPacket);
      frameCount++;
      if(avReadResult != 0){
        if (avReadResult != AVERROR_EOF) {
            LOGE("av_read_frame error: %s", stringForAVErrorNumber(avReadResult));
        }else{
            LOGI("End of input file");
        }
        continueRecording = 0;
      }

      AVStream *outStream = outputFormatContext->streams[inputPacket->stream_index];
      writeFrameResult = av_interleaved_write_frame(outputFormatContext, inputPacket);
      if(writeFrameResult < 0){
          LOGE("av_interleaved_write_frame error: %s", stringForAVErrorNumber(avReadResult));
      }
  }

  // Finalize the output file
  int writeTrailerResult = writeFileTrailer(outputFormatContext);
  if(writeTrailerResult < 0){
      LOGE("av_write_trailer error: %s", stringForAVErrorNumber(writeTrailerResult));
  }
  LOGI("Wrote trailer");
}

有关所有辅助功能(camelCase 中的功能)的完整内容,请参阅我在Github 上的完整项目。有问题吗?我很乐意详细说明。

【讨论】:

  • 我试试看告诉你,你能把你的邮箱地址发给我吗,
  • 我已经从 GIT 下载了你的示例应用程序,但它似乎只适用于 android 4.4
  • 正如你所说,我知道“如何将原生 .c 文件连接到相应 .java 文件中的原生方法”我想知道压缩视频的原生 c 代码,我试图执行 ut Github项目,但它似乎适用于 android 4.4
  • 我链接的 GitHub 项目是 MediaCocec 和 FFmpeg 的实验,这就是 Android 4.3 要求的来源。您要在应用程序中包含的核心文件是jni/ 文件夹和FFmpegWrapper.java。您将修改 FFmpegWrapper.c 和 FFmpegWrapper.java 以仅公开我在响应中包含的一个函数。当您需要配置 FFmpeg 库以满足您的需要时,请参阅我在 building FFmpeg for Android 上的注释。
  • 它只是复制视频而不是压缩大小。
猜你喜欢
  • 2014-05-28
  • 1970-01-01
  • 2014-07-02
  • 2017-03-02
  • 2015-10-22
  • 2021-02-27
  • 1970-01-01
  • 2016-06-09
  • 1970-01-01
相关资源
最近更新 更多