gpt4 book ai didi

ffmpeg - JavaCV:avformat_open_input() 挂起(不是网络,而是使用自定义 AVIOContext)

转载 作者:行者123 更新时间:2023-12-04 23:04:58 36 4
gpt4 key购买 nike

我正在使用自定义 AVIOContext 将 FFMpeg 与 java IO 连接起来。函数avformat_open_input()永远不会回来。我在网上搜索过类似的问题,都是由于网络故障或服务器配置错误造成的。但是,我根本没有使用网络,正如您在以下小程序中看到的那样:

package com.example;

import org.bytedeco.javacpp.*;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import static org.bytedeco.javacpp.avcodec.*;
import static org.bytedeco.javacpp.avformat.*;
import static org.bytedeco.javacpp.avutil.*;
import static org.bytedeco.javacpp.avdevice.*;
import static org.bytedeco.javacpp.avformat.AVFormatContext.*;

public class Test {

public static void main(String[] args) throws Exception {
File dir = new File(System.getProperty("user.home"), "Desktop");
File file = new File(dir, "sample.3gp");
final RandomAccessFile raf = new RandomAccessFile(file, "r");

Loader.load(avcodec.class);
Loader.load(avformat.class);
Loader.load(avutil.class);
Loader.load(avdevice.class);
Loader.load(swscale.class);
Loader.load(swresample.class);

avcodec_register_all();
av_register_all();
avformat_network_init();
avdevice_register_all();

Read_packet_Pointer_BytePointer_int reader = new Read_packet_Pointer_BytePointer_int() {
@Override
public int call(Pointer pointer, BytePointer buf, int bufSize) {
try {
byte[] data = new byte[bufSize]; // this is inefficient, just use as a quick example
int read = raf.read(data);

if (read <= 0) {
System.out.println("EOF found.");
return AVERROR_EOF;
}

System.out.println("Successfully read " + read + " bytes of data.");
buf.position(0);
buf.put(data, 0, read);
return read;
} catch (Exception ex) {
ex.printStackTrace();
return -1;
}
}
};

Seek_Pointer_long_int seeker = new Seek_Pointer_long_int() {
@Override
public long call(Pointer pointer, long offset, int whence) {
try {
raf.seek(offset);
System.out.println("Successfully seeked to position " + offset + ".");
return offset;
} catch (IOException ex) {
return -1;
}
}
};

int inputBufferSize = 32768;
BytePointer inputBuffer = new BytePointer(av_malloc(inputBufferSize));
AVIOContext ioContext = avio_alloc_context(inputBuffer, inputBufferSize, 1, null, reader, null, seeker);
AVInputFormat format = av_find_input_format("3gp");
AVFormatContext formatContext = avformat_alloc_context();
formatContext.iformat(format);
formatContext.flags(formatContext.flags() | AVFMT_FLAG_CUSTOM_IO);
formatContext.pb(ioContext);

// This never returns. And I can never get result.
int result = avformat_open_input(formatContext, "", format, null);

// all clean-up code omitted for simplicity
}

}

下面是我的示例控制台输出:
Successfully read 32768 bytes of data.
Successfully read 32768 bytes of data.
Successfully read 32768 bytes of data.
Successfully read 32768 bytes of data.
Successfully read 32768 bytes of data.
Successfully read 7240 bytes of data.
EOF found.

我检查了与文件大小相对应的字节总和; EOF 也被命中,这意味着文件被完全读取。其实我有点怀疑为什么 avformat_open_input()甚至会读取整个文件并且仍然没有返回?我的所作所为一定有问题。任何专家都可以阐明一些观点或指出正确的方向吗?我是 javacv 的新手和 ffmpeg尤其是使用 Buffer 进行编程s 和东西。欢迎任何帮助、建议或批评。提前致谢。

最佳答案

好的,现在我找到了问题所在。我有 误解 文档和 被忽视的我发现的大多数例子。我的错。

根据 ffmpeg 上的文档:

AVIOContext* avio_alloc_context (unsigned char* buffer,
int buffer_size,
int write_flag,
void* opaque,
int(*)(void *opaque, uint8_t *buf, int buf_size) read_packet,
int(*)(void *opaque, uint8_t *buf, int buf_size) write_packet,
int64_t(*)(void *opaque, int64_t offset, int whence) seek
)

第三个参数 write_flag以下列方式使用:

write_flag - 设置为 1如果缓冲区应该是可写的,0否则。

实际上,这意味着如果 AVIOContext用于数据输出(即写入), write_flag应设置为 1 .否则,如果上下文用于数据输入(即读取),则应将其设置为 0 .

在我发布的问题中,我通过了 1作为 write_flag它在阅读时引起了问题。路过 0而是解决了问题。

后来我重新阅读了我找到的所有示例,所有 avio_alloc_context()通话使用 0 ,而不是 1阅读时。因此,这进一步表明了我遇到问题的原因。

最后,我将发布修改后的代码并纠正了问题,以作为将来的引用。
package com.example;

import org.bytedeco.javacpp.*;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import static org.bytedeco.javacpp.avformat.*;
import static org.bytedeco.javacpp.avutil.*;
import static org.bytedeco.javacpp.avformat.AVFormatContext.*;

public class Test {

public static void main(String[] args) throws Exception {
File dir = new File(System.getProperty("user.home"), "Desktop");
File file = new File(dir, "sample.3gp");
final RandomAccessFile raf = new RandomAccessFile(file, "r");

Loader.load(avformat.class);
Loader.load(avutil.class);

av_register_all();
avformat_network_init();

Read_packet_Pointer_BytePointer_int reader = new Read_packet_Pointer_BytePointer_int() {
@Override
public int call(Pointer pointer, BytePointer buf, int bufSize) {
try {
byte[] data = new byte[bufSize]; // this is inefficient, just use as a quick example
int read = raf.read(data);

if (read <= 0) {
// I am still unsure as to return '0', '-1' or 'AVERROR_EOF'.
// But according to the following link, it should return 'AVERROR_EOF',
// http://www.codeproject.com/Tips/489450/Creating-Custom-FFmpeg-IO-Context
// btw 'AVERROR_EOF' is a nasty negative number, '-541478725'.
return AVERROR_EOF;
}

buf.position(0);
buf.put(data, 0, read);
return read;
} catch (Exception ex) {
ex.printStackTrace();
return -1;
}
}
};

Seek_Pointer_long_int seeker = new Seek_Pointer_long_int() {
@Override
public long call(Pointer pointer, long offset, int whence) {
try {
if (whence == AVSEEK_SIZE) {
// Returns the entire file length. If not supported, simply returns a negative number.
// https://www.ffmpeg.org/doxygen/trunk/avio_8h.html#a427ff2a881637b47ee7d7f9e368be63f
return raf.length();
}

raf.seek(offset);
return offset;
} catch (IOException ex) {
ex.printStackTrace();
return -1;
}
}
};

int inputBufferSize = 32768;
BytePointer inputBuffer = new BytePointer(av_malloc(inputBufferSize));

AVIOContext ioContext = avio_alloc_context(inputBuffer,
inputBufferSize,
0, // CRITICAL, if the context is for reading, it should be ZERO
// if the context is for writing, then it is ONE
null,
reader,
null,
seeker);

AVInputFormat format = av_find_input_format("3gp");
AVFormatContext formatContext = avformat_alloc_context();
formatContext.iformat(format);
formatContext.flags(formatContext.flags() | AVFMT_FLAG_CUSTOM_IO);
formatContext.pb(ioContext);

// Now this is working properly.
int result = avformat_open_input(formatContext, "", format, null);
System.out.println("result == " + result);

// all clean-up code omitted for simplicity
}

}

引用:
  • AVSEEK_SIZE documentation
  • avio_alloc_context() documentation

  • 附加引用:(我没有足够的声誉点来获得更多链接,但我发现这些示例对我很有帮助,所以我还是将它们粘贴为纯文本)
  • 在以下位置创建自定义 FFmpeg IO-Context(CodeProject 示例):http://www.codeproject.com/Tips/489450/Creating-Custom-FFmpeg-IO-Context
  • 另一个显示使用 write_flag 的示例在 avio_alloc_context()在:https://www.ffmpeg.org/doxygen/2.5/avio_reading_8c-example.html#a20
  • 关于ffmpeg - JavaCV:avformat_open_input() 挂起(不是网络,而是使用自定义 AVIOContext),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33109402/

    36 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com