libav 형식으로 메모리에 있는 파일 읽기
현재 서버에서 보낸 작은 비디오 파일을 읽으려고 하는 중입니다.
libav 형식을 사용하여 파일을 읽으려면 다음을 호출해야 합니다.
av_open_input_file(&avFormatContext, "C:\\path\\to\\video.avi", 0, 0, 0);
문제는 이 경우 파일이 디스크에 있는 것이 아니라 메모리에 있다는 것입니다.
지금 제가 하고 있는 일은 파일을 다운로드해서 임시 이름을 사용해서 디스크에 쓴 다음에 호출하는 것입니다.av_open_input_file
매우 깨끗한 해결책이 아닌 임시 파일 이름을 사용합니다.
사실 제가 원하는 것은 다음과 같은 기능입니다.av_open_custom(&avFormatContext, &myReadFunction, &mySeekFunction);
서류에서 아무것도 못 찾았어요파일 이름이 도서관에서 사용하는 형식을 결정하는 데 도움이 되는 것이 아니기 때문에 기술적으로 가능하다고 생각합니다.
그렇다면 이러한 기능이나 av_open_input_file의 대안이 있습니까?
이 문제를 몇 시간 동안 연구했는데도 이 사이트에 문제를 올린 직후에 항상 혼자 해결책을 찾는다는 것이 재미있습니다.
사실 초기화를 해야 합니다.avFormatContext->pb
부르기 전에av_open_input
, 가짜 파일명을 전달해 줄 겁니다이것은 설명서에 쓰여 있는 것이 아니라 도서관의 소스 코드에 직접 있는 해설에 쓰여져 있습니다.
isstream에서 로드하려는 경우의 예시 코드(테스트되지 않은 경우, 동일한 문제를 가진 사람이 아이디어를 얻을 수 있도록 함)
static int readFunction(void* opaque, uint8_t* buf, int buf_size) {
auto& me = *reinterpret_cast<std::istream*>(opaque);
me.read(reinterpret_cast<char*>(buf), buf_size);
return me.gcount();
}
std::ifstream stream("file.avi", std::ios::binary);
const std::shared_ptr<unsigned char> buffer(reinterpret_cast<unsigned char*>(av_malloc(8192)), &av_free);
const std::shared_ptr<AVIOContext> avioContext(avio_alloc_context(buffer.get(), 8192, 0, reinterpret_cast<void*>(static_cast<std::istream*>(&stream)), &readFunction, nullptr, nullptr), &av_free);
const auto avFormat = std::shared_ptr<AVFormatContext>(avformat_alloc_context(), &avformat_free_context);
auto avFormatPtr = avFormat.get();
avFormat->pb = avioContext.get();
avformat_open_input(&avFormatPtr, "dummyFilename", nullptr, nullptr);
이것은 좋은 정보이고 저에게 많은 도움이 되었지만, 사람들이 알아야 할 몇 가지 문제들이 있습니다.libavformat은 avio_context_alloc에 제공한 버퍼를 엉망으로 만들 수도 있고 그럴 수도 있습니다.이것은 정말 성가신 이중 오류나 가능한 메모리 유출로 이어집니다.문제를 찾기 시작했을 때 완벽하게 해결해 준 https://lists.ffmpeg.org/pipermail/libav-user/2012-December/003257.html 을 발견했습니다.
이 일을 정리할 때의 나의 해결책은 그냥 전화하는 것입니다.
av_free(avioContext->buffer)
그런 다음 원하는 경우 자신의 버퍼 포인터(avio_alloc_context call에 할당한)를 NULL로 설정합니다.
Tomaka17의 훌륭한 답변은 std::istream이 아닌 Qt QIO device를 사용하여 유사한 문제를 해결하는 좋은 출발을 하게 해주었습니다.Tomaka17의 솔루션 측면과 http://cdry.wordpress.com/2009/09/09/using-custom-io-callbacks-with-ffmpeg/ 의 관련 경험 측면을 융합해야 한다는 것을 알게 되었습니다.
사용자 지정 읽기 기능은 다음과 같습니다.
int readFunction(void* opaque, uint8_t* buf, int buf_size)
{
QIODevice* stream = (QIODevice*)opaque;
int numBytes = stream->read((char*)buf, buf_size);
return numBytes;
}
...사용자 지정 Seek 기능도 만들어야 했습니다.
int64_t seekFunction(void* opaque, int64_t offset, int whence)
{
if (whence == AVSEEK_SIZE)
return -1; // I don't know "size of my handle in bytes"
QIODevice* stream = (QIODevice*)opaque;
if (stream->isSequential())
return -1; // cannot seek a sequential stream
if (! stream->seek(offset) )
return -1;
return stream->pos();
}
...그리고 저는 이렇게 묶었습니다.
...
const int ioBufferSize = 32768;
unsigned char * ioBuffer = (unsigned char *)av_malloc(ioBufferSize + FF_INPUT_BUFFER_PADDING_SIZE); // can get av_free()ed by libav
AVIOContext * avioContext = avio_alloc_context(ioBuffer, ioBufferSize, 0, (void*)(&fileStream), &readFunction, NULL, &seekFunction);
AVFormatContext * container = avformat_alloc_context();
container->pb = avioContext;
avformat_open_input(&container, "dummyFileName", NULL, NULL);
...
참고로 저는 아직 메모리 관리 문제를 해결하지 못했습니다.
언급URL : https://stackoverflow.com/questions/9604633/reading-a-file-located-in-memory-with-libavformat
'programing' 카테고리의 다른 글
git가 .gitignore 파일에 없는 파일을 무시하는 이유는 무엇입니까? (0) | 2023.10.16 |
---|---|
템플릿 파일이 변경되면 Plask 앱 다시 로드 (0) | 2023.10.16 |
PHP를 이용하여 mysql 또는 pdo에서 ALTER 문의 결과를 어떻게 보여주나요? (0) | 2023.10.11 |
a + b + c = 1000인 피타고라스 삼중항 찾기 (0) | 2023.10.11 |
우커머스 수동으로 주문 추가:ajax 호출에서 제품을 필터링하는 방법 (0) | 2023.10.11 |