Android平台如何将单张图片与视频合并生成MP4?求可用实现库
Hey there! Let’s figure out how to merge a single image with a video into an MP4 on Android—since you’ve already tried FFmpeg and OpenCV without luck, let’s dig into actionable fixes and alternative solutions.
Chances are, the issue with FFmpeg wasn’t the library itself, but either the command parameters you used or a missing encoder in your build. Let’s use MobileFFmpeg—a pre-compiled, Android-friendly FFmpeg wrapper that includes all necessary codecs, so you don’t have to mess with native compilation.
Step 1: Add Dependency
Add this to your app-level build.gradle (Module level):
implementation 'com.arthenica:mobile-ffmpeg-full:4.4.LTS'
Step 2: Example Code for Merging Image + Video
Let’s say you want the image to play for 3 seconds at the start of the video, then transition to the original video. Here’s the code:
import com.arthenica.mobileffmpeg.FFmpeg; import java.io.File; // Define paths (replace with your actual file paths) String imagePath = "/storage/emulated/0/Download/your_image.jpg"; String inputVideoPath = "/storage/emulated/0/Download/your_input.mp4"; String tempImageVideoPath = "/storage/emulated/0/Download/temp_image_video.mp4"; String outputPath = "/storage/emulated/0/Download/final_output.mp4"; // First, convert the image into a 3-second video clip String[] imageToVideoCmd = new String[]{ "-loop", "1", // Loop the image to create a continuous video clip "-i", imagePath, // Input image file path "-t", "3", // Duration of the image clip (3 seconds) "-c:v", "libx264", // Use H.264 codec (universally compatible with MP4) "-r", "30", // Frame rate (match your input video for smooth transition) "-pix_fmt", "yuv420p", // Critical pixel format for MP4 player compatibility "-c:a", "aac", // Dummy audio codec (avoids errors even if image has no audio) "-strict", "experimental", "-shortest", tempImageVideoPath }; // Execute the first command to generate the image clip int result1 = FFmpeg.execute(imageToVideoCmd); if (result1 == FFmpeg.RETURN_CODE_SUCCESS) { // Now concatenate the image clip and original video String[] concatCmd = new String[]{ "-i", "concat:" + tempImageVideoPath + "|" + inputVideoPath, "-c", "copy", // Copy codecs directly (fast, no re-encoding if formats match) outputPath }; int result2 = FFmpeg.execute(concatCmd); if (result2 == FFmpeg.RETURN_CODE_SUCCESS) { // Clean up the temporary file if needed new File(tempImageVideoPath).delete(); } }
Key Fixes You Might Have Missed
- Always use
yuv420ppixel format—many media players won’t recognize MP4s with other formats. - Use the
fullvariant of MobileFFmpeg to ensure all codecs (like libx264) are included. - Add proper storage permissions (Android 10+ requires using
MediaStoreorMANAGE_EXTERNAL_STORAGEfor file access).
If you want to avoid FFmpeg entirely, you can use Android’s built-in MediaCodec and MediaMuxer APIs. This is more code-heavy but gives you full control over the process.
Core Idea
- Convert the image into a sequence of video frames (render the bitmap to a surface, then capture YUV frames).
- Write those frames to
MediaMuxerfor your desired duration (e.g., 3 seconds). - Decode the original video’s frames and audio, then write them to the same
MediaMuxer.
Sample Code Snippet (Simplified)
import android.media.MediaCodec; import android.media.MediaFormat; import android.media.MediaMuxer; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import java.nio.ByteBuffer; // Initialize MediaMuxer for MP4 output MediaMuxer muxer = new MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); // Step 1: Write image frames to muxer Bitmap imageBitmap = BitmapFactory.decodeFile(imagePath); int width = imageBitmap.getWidth(); int height = imageBitmap.getHeight(); // Create a video track in the muxer MediaFormat videoFormat = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, width, height); videoFormat.setInteger(MediaFormat.KEY_BIT_RATE, 1000000); videoFormat.setInteger(MediaFormat.KEY_FRAME_RATE, 30); videoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); int videoTrackIndex = muxer.addTrack(videoFormat); muxer.start(); // Write image frames for 3 seconds long startTime = System.currentTimeMillis(); while (System.currentTimeMillis() - startTime < 3000) { // Convert Bitmap to YUV buffer (use a helper function for this conversion) ByteBuffer yuvBuffer = convertBitmapToYUV(imageBitmap, width, height); MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo(); bufferInfo.offset = 0; bufferInfo.size = yuvBuffer.remaining(); bufferInfo.presentationTimeUs = (System.currentTimeMillis() - startTime) * 1000; bufferInfo.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME; muxer.writeSampleData(videoTrackIndex, yuvBuffer, bufferInfo); // Sleep to maintain frame rate try { Thread.sleep(1000 / 30); } catch (InterruptedException e) { e.printStackTrace(); } } // Step 2: Write original video frames and audio (omitted for brevity) // Use MediaExtractor to read the input video, decode frames with MediaCodec, then write to muxer
Note: You’ll need a helper function convertBitmapToYUV to convert the RGB bitmap to YUV 420 format—you can use RenderScript or manual pixel conversion for this.
If FFmpeg still isn’t working for you, try these options:
- MP4Parser: A lightweight library for manipulating MP4 file structures. First, convert your image to a short MP4 clip (using MediaCodec), then use MP4Parser to concatenate it with your original video.
- Glide + MediaMuxer: Use Glide to load and process the image, then render it as video frames to feed into
MediaMuxeralongside the original video’s frames.
- FFmpeg Issues: If you were using a self-compiled FFmpeg build, you probably missed including codecs like
libx264—MobileFFmpeg’s full variant fixes this. Also, double-check your command parameters for typos or missing flags (like-pix_fmt yuv420p). - OpenCV Issues: OpenCV’s
VideoWritercan be finicky on Android. Make sure you’re using the correct four-character code for MP4 (CV_FOURCC('M','P','4','V')) and matching the input video’s resolution/frame rate. Also, ensure OpenCV is properly integrated with your Android project.
内容的提问来源于stack exchange,提问作者n00r_ay




