与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
感谢大家的宝贵时间。
答案 0 :(得分:1)
从上面的注释开始实施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/
答案 1 :(得分:1)
是的,编码器的输入缓冲区较小,因为它希望输入具有指定的尺寸。顾名思义,仅编码器进行编码。
我将您的问题更多地理解为“为什么”而不是“如何”问题,因此,我只会指出您在哪里可以找到“为什么”
解码后的帧是YUV图像(建议快速浏览wikipedia article),如果我没记错,但设备之间可能有所不同,通常是NV21。为此,我建议您使用一个库,因为图像的每个平面都需要不同程度地缩小,并且通常需要进行过滤。请查看libYUV。如果您对实际的尺寸调整算法感兴趣,请查看this和实现this。
如果不需要使用字节缓冲区来处理解码和编码,我建议使用已经提到过的表面。与解码字节缓冲区相比,它具有多个优点。
希望这能回答您的一些问题。