1

I have a problem when trying to open a binary file containing raw audio data in opus format. When I try to open this file, the library returns an error: Unknown input format: opus.

How can I open this file ?

I need to open it and write all the raw audio data to an audio container. I understand that the opus format is intended only for encoding. I realized this using command:

$ ffmpeg -formats | grep Opus

ffmpeg version 3.4.4 Copyright (c) 2000-2018 the FFmpeg developers
  E opus Ogg Opus # For only encoding

Then what format should I use to open this file ? With ogg ? I tried, but there are also problems with opening the outgoing file. I provide the code that shows only the necessary part to open the file:

int main(int argc, char *argv[])
{
    // ...

    av_register_all();

    AVFormatContext *iFrmCtx = nullptr;
    AVFormatContext *oFrmCtx = nullptr;
    AVPacket packet;

    const char *iFilename = "opus.bin"; // Raw audio data with `opus` format
    const char *oFilename = "opus.mka"; // Audio file with `opus` audio format

    AVDictionary* frmOpts = nullptr;
    const qint32 smpRateErrorCode = av_dict_set_int(&frmOpts, "sample_rate", 8000,  0);
    const qint32 bitRateErrorCode = av_dict_set_int(&frmOpts, "bit_rate",    64000, 0);
    const qint32 channelErrorCode = av_dict_set_int(&frmOpts, "channels",    2,     0);
    if (smpRateErrorCode < 0 ||
            bitRateErrorCode < 0 ||
                channelErrorCode < 0) {
        return EXIT_FAILURE;
    }

    AVInputFormat *iFrm = av_find_input_format("opus"); // Error: Unknown input format
    if (iFrm == nullptr) {
        av_dict_free(&frmOpts);
        return EXIT_FAILURE;
    }

    qint32 ret = 0;
    if ((ret = avformat_open_input(&iFrmCtx, iFilename, iFrm, &frmOpts)) < 0) {
        av_dict_free(&frmOpts);
        return EXIT_FAILURE;
    }

    // We're doing something...
}
bbdd
  • 37
  • 1
  • 11
  • What do you mean by raw audio data in opus format? Opus is not self-delimiting, it needs a container (OGG, Matroska, ISO BMFF maybe/proposed, UDP/RTP). In RFC 6716 there's an Appendix B for self-delimiting framing but that's typically used to pack packets for multiple streams / channels and it still relies on the transport layer to signal it. All the demuxers I know in FFmpeg are for OGG. Anyway, with a dummy `image2` demuxer it seems at least capable of detecting opus extracted from a RTP payload, not sure if it decodes in all cases and it's a bad idea anyway. – aergistal Oct 06 '20 at 19:42
  • @aergistal, By opus format, I mean that the audio data is encoded in opus ( it can also be pcm_alaw audio data, pcm_mulaw, and so on ). In practice, I get RTP packets, with opus audio data stored in the payload. Then I extract the payload from the RTP packet and send it to the audio encoder. In my example, I just want to extract all the audio data in the opus format from file and pack it in Matroska format. – bbdd Oct 06 '20 at 19:59
  • @aergistal, There are no problems with the audio data `alaw`, `mulaw`, `s16le`, `s16be` (because `avformat_open_input` finds these formats ), but I have problems with opus, which are described in the question itself. If you want, I can give you my own code (`~300 lines of code`), which I use to encode raw audio data into an audio file :) – bbdd Oct 06 '20 at 20:05
  • Like I said I don't see any demuxer for raw payloads, only OGG. But you could write a quick demuxer which sets the payload length and then pass it to `libopus` (optional codec, you need to enable during FFmpeg configure). Haven't tried it though. – aergistal Oct 08 '20 at 12:04
  • @aergistal, to write a demuxer, is [this](https://ffmpeg.org/doxygen/trunk/group__lavf__decoding.html) enough for me to understand how to implement it ? Also, what do you mean by this statement: `you need to enable during FFmpeg configure`. – bbdd Oct 08 '20 at 12:17
  • just take a look at the existing ones in `libavformat`. FFmpeg supports decoding with `libopus`. You need to install the lib and then pass `--enable-libopus` during `configure` before compiling FFmpeg: https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu#libopus – aergistal Oct 08 '20 at 13:22
  • @aergistal, when starting the `ffmpeg` tool, `libopus` is already specified as arguments: `configuration: ... --enable-libopenjpeg --enable-libopus --enable-libpulse ... ` – bbdd Oct 08 '20 at 13:54

1 Answers1

0

As said before Opus is not self-delimiting, it needs a container. and since you got the raw data from rtp payload, and the opus codecs is a dynamic codecs (with dynamic payload size) you can't use ffmpeg AVFormatContext to read raw data from the file.

But you can work around this issue and instead of using (av_read_frame) to fill the AVPacket to decode them you can manually fill the AVPacket data and size and then push it to the decoder.

note that you should also update the pts and dts for each AVPacket .

  • What fields do I need to fill in ? I think I only need to fill in `buf::data`, `buf::size`, `pts`, `dts`. But what exactly to specify as `pts` and `dts` I do not know. More precisely, I do not know how to correctly calculate the current value of `pts` and `dts`. – bbdd Nov 04 '20 at 10:46
  • pts and dts incremented by 960 for every packet, and started with zero for 48KHz opus stream – Asmaa Tabbaa Nov 04 '20 at 12:14
  • Is there a link to a description of how `pts` and `dts` are calculated for a specific codec? I mean, if I get `OPUS` data with a sampling rate of `44100` instead of `48000`, will there be any changes in the `pts` and `dts` ? Or as an example, what will be the increment of the `GSM` codec. – bbdd Nov 04 '20 at 13:31
  • yes sure it varies from one codec to another for example mulaw codec incremented by 1024. you can check this question to understand it better https://stackoverflow.com/questions/43333542/what-is-video-timescale-timebase-or-timestamp-in-ffmpeg – Asmaa Tabbaa Nov 04 '20 at 15:30
  • Strange, because when viewing `pts` and `dts` fields in audio file with the `opus` audio codec, the values were uneven. You can view an example of the `pts` and `dts` output of any audio file using this command: `ffprobe -show_frames aud-opus-48000SampleRate-36000BitRate-2Channel.mka`. You need to look at the `pkt_pts` and `pkt_dts` fields. – bbdd Nov 04 '20 at 16:53
  • I have test the command you have wrote to an opus file and I can find that the difference between pts fields for any two sequenced frames is 960 !! – Asmaa Tabbaa Nov 06 '20 at 12:55
  • It is strange, since I have now tested an audio file with opus `codec` again - the result is **`20`** – bbdd Nov 06 '20 at 14:20
  • And What is the value of pkt_duration and pkt_duration_time? – Asmaa Tabbaa Nov 07 '20 at 16:08