Das Problem ist, dass sich die Datei in diesem Fall nicht auf der Festplatte, sondern im Speicher befindet.
Im Moment lade ich die Datei herunter, schreibe sie unter einem temporären Namen auf die Festplatte und rufe sie dann auf av_open_input_file mit dem temporären Dateinamen, was keine sehr saubere Lösung ist.
In der Tat, was ich will, ist eine Funktion wie av_open_custom(&avFormatContext, &myReadFunction, &mySeekFunction); aber in der Dokumentation habe ich nichts gefunden. Ich denke, es ist technisch möglich, da der Name der Datei der Bibliothek nicht hilft, das verwendete Format zu bestimmen.
Gibt es also eine solche Funktion oder eine Alternative zu av_open_input_file?
Tomaka17
Es ist komisch, wie ich die Lösung immer selbst finde, gleich nachdem ich die Frage auf dieser Seite gepostet habe, obwohl ich stundenlang an diesem Problem gearbeitet habe.
Tatsächlich müssen Sie initialisieren avFormatContext->pb vor dem Anruf av_open_input, und übergeben Sie ihm einen gefälschten Dateinamen. Dies steht nicht in der Dokumentation, sondern in einem Kommentar direkt im Quellcode der Bibliothek.
Beispielcode, wenn Sie von einem istream laden möchten (ungetestet, nur damit jemand, der das gleiche Problem hat, auf die Idee kommt)
Diese Lösung funktioniert großartig, bis ich suchen muss. Irgendeine Idee, wie man diese Lösung mit der Suche zum Laufen bringt? Ich verwende derzeit avformat_seek_file mit dem Formatkontext für den Videostream und den Audiostream separat. Wenn Sie die Suche nach einer Streaming-Datei (URL) verwenden, funktioniert dies hervorragend. Wenn ich mit dieser Methode auf einem lokalen mp4 bin, bekomme ich [mov,mp4,m4a,3gp,3g2,mj2 @ 00ee8360] stream 0, offset 0xfd97fc: partial file.
– leetNachtschatten
20. März 2016 um 23:50 Uhr
Ich bekomme auch einen Absturz in x64, aber nicht in x86, wenn ich diese Methode verwende, stürzt innerhalb von avformat_open_input ab.
– leetNachtschatten
7. April 2016 um 16:13 Uhr
Hallo, ich scheine ‘null’ auf `avFormat.get()’ zu bekommen – kennen Sie vielleicht den Grund dafür?
– dk123
24. Juni 2016 um 21:17 Uhr
Das sind großartige Informationen und haben mir ziemlich geholfen, aber es gibt ein paar Probleme, die die Leute beachten sollten. libavformat kann und wird mit Ihrem Puffer herumspielen, den Sie avio_alloc_context gegeben haben. Dies führt zu wirklich ärgerlichen Double-Free-Fehlern oder möglicherweise Speicherlecks. Als ich anfing, nach dem Problem zu suchen, fand ich es https://lists.ffmpeg.org/pipermail/libav-user/2012-December/003257.html was es perfekt getroffen hat.
Meine Problemumgehung beim Aufräumen dieser Arbeit besteht darin, einfach weiterzumachen und anzurufen
av_free(avioContext->buffer)
und setzen Sie dann Ihren eigenen Pufferzeiger (den Sie für Ihren avio_alloc_context-Aufruf zugewiesen haben) auf NULL, wenn Sie sich dafür interessieren.
Vielen Dank. Dies direkt vor av_free(avioContext) zu tun, löste mein Speicherleckproblem!
– Michel
3. Dezember 2014 um 15:04 Uhr
@keefer heutzutage, vielleicht wegen der von Ihnen verlinkten Beschwerde, scheint es möglich zu sein, NULL als Puffer und 0 als Größe zu übergeben, und ffmpeg wird das Vernünftige tun, anstatt diese verrückte Art der Speicherverwaltung zu erfordern, bei der Sie einen Puffer zuweisen und es kann entscheiden, es nach Belieben neu zuzuweisen und Sie mit einem baumelnden Zeiger zurückzulassen.
– Benutzer1593842
18. April 2019 um 22:15 Uhr
Die ausgezeichnete Antwort von Tomaka17 gab mir einen guten Start zur Lösung eines analogen Problems mit Qt QIODevice anstelle von std::istream. Ich stellte fest, dass ich Aspekte der Lösung von Tomaka17 mit Aspekten der damit verbundenen Erfahrung bei kombinieren musste http://cdry.wordpress.com/2009/09/09/using-custom-io-callbacks-with-ffmpeg/
Meine benutzerdefinierte Read-Funktion sieht so aus:
int readFunction(void* opaque, uint8_t* buf, int buf_size)
{
QIODevice* stream = (QIODevice*)opaque;
int numBytes = stream->read((char*)buf, buf_size);
return numBytes;
}
… aber ich musste auch eine benutzerdefinierte Seek-Funktion erstellen:
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();
}