【问题标题】:Video Transcode with Android MediaCodec使用 Android MediaCodec 进行视频转码
【发布时间】:2020-03-21 02:29:09
【问题描述】:

在 Android MediaCodec 上苦苦挣扎,我正在寻找一个直接的过程来更改 Android 中视频文件的分辨率。

目前我正在尝试一种单线程转码方法,它逐步完成所有工作,以便我可以很好地理解它,并且在高层次上看起来如下:

public void TranscodeVideo()
{
    // Extract
    MediaTrack[] tracks = ExtractTracks(InputPath);

    // Decode
    MediaTrack videoTrack = tracks.Where(o => o.IsVideo).FirstOrDefault();
    MediaTrack rawVideoTrack = DecodeTrack(videoTrack);

    // Edit?
    // ResizeVideoTrack(rawVideoTrack);

    // Encode
    MediaFormat newFormat = MediaHelper.CreateVideoOutputFormat(videoTrack.Format);
    MediaTrack encodeVideodTrack = EncodeTrack(rawVideoTrack , newFormat);

    // Muxe
    encodeVideodTrack.Index = videoTrack.Index;
    tracks[Array.IndexOf(tracks, videoTrack)] = encodeVideodTrack;
    MuxeTracks(OutputPath, tracks);
}

提取工作正常,返回仅包含音频的轨道和仅包含视频的轨道。 Muxing 再次结合之前的两个轨道可以很好地工作。解码有效,但我不知道如何检查它,轨道上的原始帧比原始帧重得多,所以我认为它是正确的。

问题

编码器输入缓冲区大小小于原始帧大小,并且还与编码配置格式有关,因此我假设我需要以某种方式调整帧大小但我没有发现任何有用的东西。这点我说得对吗?我错过了什么?调整原始视频帧大小的方法是什么?有什么帮助吗? :S

PD

  • 也许您会注意到我使用 C# (Xamarin.Android) 来获得更多乐趣。但底层 API 当然是 Java。
  • 我使用的是 ByteBuffers,而不是 Surfaces,因为它看起来更容易。我将是使用表面的下一步,欢迎任何建议。
  • 我知道单线程进程的效率非常低,但让它变得简单。下一步是将解码器输出缓冲区连接到编码器输入缓冲区。
  • 我浏览了 PhilLabGrafikaBigflake 示例,但似乎没有什么对我很有用。
  • 避免在 Android 上使用 ffmpeg。

感谢大家的宝贵时间。

【问题讨论】:

  • 你用过libVLC吗?我刚刚将它集成到我的 RTSP 流媒体应用程序中,它可以处理转码和 vlc 附带的所有爵士乐
  • 不,看起来很酷,我会尝试,你能给出一个使用 libVLC 进行转码的快速 C# 示例吗?

标签: java android android-mediacodec


【解决方案1】:

您是对的,编码器的输入缓冲区大小较小,因为它希望输入具有指定的尺寸。顾名思义,仅编码器进行编码。

我认为您的问题更多的是“为什么”而不是“如何”问题,所以我只会指出您可以找到“为什么”的位置

解码后的帧是 YUV 图像(建议快速浏览wikipedia article),如果我没记错的话,通常是NV21,但可能因设备而异。为此,我建议您使用一个库,因为图像的每个平面都需要以不同方式缩小,并且通常会负责过滤。查看libYUV。如果您对实际的大小调整算法感兴趣,请查看this 和实现this

如果您不需要使用字节缓冲区处理解码和编码,我建议使用您已经提到的表面。与解码到字节缓冲区相比,它具有多种优势。

  • 由于在本机缓冲区和应用程序分配的缓冲区之间没有副本,内存效率更高,本机缓冲区只是在表面之间交换。
  • 如果您计划渲染帧,无论是调整大小还是显示,都可以由设备图形处理器完成。关于如何做到这一点,请查看 BigFlakes DecodeEditEncode 测试。

希望这能回答你的一些问题。

【讨论】:

    【解决方案2】:

    放弃上面的评论来实现 libVLC

    将此添加到您的应用根目录的 build.gradle

    allprojects {
        repositories {
           ...
           maven {
               url 'https://jitpack.io'
           }
       }
    }
    

    将此添加到依赖应用的 build.gradle

    dependancies {
        ...
        implementation 'com.github.masterwok:libvlc-android-sdk:3.0.13'
    }
    

    这是一个将 RTSP 流加载为活动的示例

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.camera_stream_layout);
    
    
        // Get URL
        this.rtspUrl = getIntent().getExtras().getString(RTSP_URL);
        Log.d(TAG, "Playing back " + rtspUrl);
    
        this.mSurface = findViewById(R.id.camera_surface);
        this.holder = this.mSurface.getHolder();
    
        ArrayList<String> options = new ArrayList<>();
        options.add("-vvv"); // verbosity
        //Add vlc transcoder options here
    
        this.libvlc = new LibVLC(getApplicationContext(), options);
        this.holder.setKeepScreenOn(true);
        //this.holder.setFixedSize();
    
        // Create media player
        this.mMediaPlayer = new MediaPlayer(this.libvlc);
        this.mMediaPlayer.setEventListener(this.mPlayerListener);
    
        // Set up video output
        final IVLCVout vout = this.mMediaPlayer.getVLCVout();
        vout.setVideoView(this.mSurface);
    
        //Set size of video to fit app screen
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
    
        ViewGroup.LayoutParams videoParams = this.mSurface.getLayoutParams();
        videoParams.width = displayMetrics.widthPixels;
        videoParams.height = displayMetrics.heightPixels;
    
        vout.setWindowSize(videoParams.width, videoParams.height);
        vout.addCallback(this);
        vout.attachViews();
    
        final Media m = new Media(this.libvlc, Uri.parse(this.rtspUrl));
        //Use this to add transcoder options m.addOption("vlc transcode options here");
        this.mMediaPlayer.setMedia(m);
        this.mMediaPlayer.play();
    }
    

    这里是vlc转码选项的文档

    https://wiki.videolan.org/Documentation:Streaming_HowTo_New/

    【讨论】:

      猜你喜欢
      • 2016-03-12
      • 1970-01-01
      • 2016-04-24
      • 2013-12-26
      • 1970-01-01
      • 2015-09-12
      • 1970-01-01
      • 1970-01-01
      • 2013-11-18
      相关资源
      最近更新 更多