【问题标题】:How to mix audio and video of different lengths using android MediaMuxer如何使用android MediaMuxer混合不同长度的音频和视频
【发布时间】:2026-02-07 21:05:02
【问题描述】:

我想使用 android mediamuxer 混合视频(1 分钟)和音频(10 秒)。我希望音频重复直到视频结束。当我使用下面的代码时,音频只播放 10 秒。有谁知道如何解决这个问题?

 mediaMuxer.start();
        while ((sampleSize = videoExtra.readSampleData(videoBuffer, 0 )) != -1) {
            videoBufferInfo.offset = 0;
            videoBufferInfo.size = sampleSize;
            videoBufferInfo.presentationTimeUs = videoExtra.getSampleTime();
            videoBufferInfo.flags = videoExtra.getSampleFlags();
            mediaMuxer.writeSampleData(videoIndex, videoBuffer, videoBufferInfo);

            videoExtra.advance();
        }



        while ((audioSize = musicExtra.readSampleData(audioBuffer, 0)) != -1) {
            audioBufferInfo.offset = 0;
            audioBufferInfo.size = audioSize;
            audioBufferInfo.presentationTimeUs = musicExtra.getSampleTime();
            audioBufferInfo.flags = musicExtra.getSampleFlags();
            mediaMuxer.writeSampleData(audioIndex, audioBuffer, audioBufferInfo);
            musicExtra.advance();
        }
        musicExtra.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);

        videoExtra.release();
        musicExtra.release();
        mediaMuxer.stop();
        mediaMuxer.release();

【问题讨论】:

    标签: android media mediamuxer


    【解决方案1】:
    1. 三个输入参数:

      字符串视频路径、字符串音频路径、字符串输出路径

    2. 获取视频时长及其曲目索引

          videoExtractor = new MediaExtractor();
          videoExtractor.setDataSource(videoPath);
          MediaFormat videoFormat = null;
      
          int videoTrackCount = videoExtractor.getTrackCount();
          //vedio max input size
          int frameMaxInputSize = 0;
          int frameRate = 0;
          long videoDuration = 0;
      
          for (int i = 0; i < videoTrackCount; i++) {
              videoFormat = videoExtractor.getTrackFormat(i);
              String mimeType = videoFormat.getString(MediaFormat.KEY_MIME);
              if (mimeType.startsWith("video/")) {
                  /*
                   * just use the first track
                   */
                  videoTrackIndex = i;
                  frameMaxInputSize = videoFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
                  frameRate = videoFormat.getInteger(MediaFormat.KEY_FRAME_RATE);
                  videoDuration = videoFormat.getLong(MediaFormat.KEY_DURATION);
                  break;
              }
          }
      
          if (videoTrackIndex  < 0 ) {
              Log.e(TAG, "Error input file:: No Vedio track");
              return;
          }
      
    3. 获取音频信息

          audioExtractor = new MediaExtractor();
          audioExtractor.setDataSource(audioPath);
          MediaFormat audioFormat = null;
      
          int audioTrackCount = audioExtractor.getTrackCount();
          audioExtractor = new MediaExtractor();
          int audioTrackCount = audioExtractor.getTrackCount();
          for (int i = 0; i < audioTrackCount; i++) {
              audioFormat = audioExtractor.getTrackFormat(i);
              String mimeType = audioFormat.getString(MediaFormat.KEY_MIME);
              if (mimeType.startsWith("audio/")) {
                  audioTrackIndex = i;
                  break;
              }
          }
      
          if (audioTrackIndex  < 0 ) {
              Log.e(TAG, "Error input file:: No Audio track");
              return;
          }
      
    4. 写入视频数据:

          MediaCodec.BufferInfo videoBufferInfo = new MediaCodec.BufferInfo();
          mediaMuxer = new MediaMuxer(outputPath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
          int writeVideoTrackIndex = mediaMuxer.addTrack(videoFormat);
          int writeAudioTrackIndex = mediaMuxer.addTrack(audioFormat);
          mediaMuxer.start();
      
          ByteBuffer byteBuffer = ByteBuffer.allocate(frameMaxInputSize);
          videoExtractor.unselectTrack(videoTrackIndex);
          videoExtractor.selectTrack(videoTrackIndex);
      
          while (true) {
              int readVideoSampleSize = videoExtractor.readSampleData(byteBuffer, 0);
              if (readVideoSampleSize < 0) {
                  videoExtractor.unselectTrack(videoTrackIndex);
                  break;
              }
              long videoSampleTime = videoExtractor.getSampleTime();
              videoBufferInfo.size = readVideoSampleSize;
              videoBufferInfo.presentationTimeUs = videoSampleTime;
              //videoBufferInfo.presentationTimeUs += 1000 * 1000 / frameRate;
              videoBufferInfo.offset = 0;
              videoBufferInfo.flags = videoExtractor.getSampleFlags();
              mediaMuxer.writeSampleData(writeVideoTrackIndex, byteBuffer, videoBufferInfo);
              videoExtractor.advance();
          }
      
    5. 写入音频数据

          long audioPresentationTimeUs = 0;
          MediaCodec.BufferInfo audioBufferInfo = new MediaCodec.BufferInfo();
          audioExtractor.selectTrack(audioTrackIndex);
          /*
           * the last audio presentation time.
           */
          long lastEndAudioTimeUs = 0;
          while (true) {
              int readAudioSampleSize = audioExtractor.readSampleData(byteBuffer, 0);
              if (readAudioSampleSize < 0) {
                  //if end of the stream, unselect
                  audioExtractor.unselectTrack(audioTrackIndex);
                  if (audioPresentationTimeUs >= videoDuration) {
                      //if has reach the end of the video time ,just exit
                      break;
                  } else {
                      //if not the end of the video time, just repeat.
                      lastEndAudioTimeUs += audioPresentationTimeUs;
                      audioExtractor.selectTrack(audioTrackIndex);
                      continue;
                  }
              }
      
              long audioSampleTime = audioExtractor.getSampleTime();
              audioBufferInfo.size = readAudioSampleSize;
              audioBufferInfo.presentationTimeUs = audioSampleTime + lastEndAudioTimeUs;
              if (audioBufferInfo.presentationTimeUs > videoDuration) {
                  audioExtractor.unselectTrack(audioTrackIndex);
                  break;
              }
              audioPresentationTimeUs = audioBufferInfo.presentationTimeUs;
              audioBufferInfo.offset = 0;
              audioBufferInfo.flags = audioExtractor.getSampleFlags();
              mediaMuxer.writeSampleData(writeAudioTrackIndex, byteBuffer, audioBufferInfo);
              audioExtractor.advance();
          }
      
    6. 释放资源。

         if (mediaMuxer != null) {
              try {
                  mediaMuxer.stop();
                  mediaMuxer.release();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      
          if (videoExtractor != null) {
              try {
                  videoExtractor.release();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      
          if (audioExtractor != null) {
              try {
                  audioExtractor.release();
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
      

    希望这会有所帮助!

    【讨论】: