leandromoreira / ffmpeg-libav-tutorial

FFmpeg libav tutorial - learn how media works from basic to transmuxing, transcoding and more. Translations: 🇺🇸 🇨🇳 🇰🇷 🇪🇸 🇻🇳 🇧🇷
https://github.com/leandromoreira/ffmpeg-libav-tutorial
BSD 3-Clause "New" or "Revised" License
9.82k stars 941 forks source link

Question about demuxing DASH #61

Closed michalSolarz closed 4 years ago

michalSolarz commented 4 years ago

Hi there @leandromoreira, That tutorial is really impressive, but I've got some question. I'm generally new in C/C++ and using ffmpeg as a library. I want to try to open DASH with following code

struct representation {
    char *url_template;
    AVIOContext pb;
    AVIOContext *input;
    AVFormatContext *parent;
    AVFormatContext *ctx;
    AVPacket pkt;
    int rep_idx;
    int rep_count;
    int stream_index;

    enum AVMediaType type;
    char id[20];
    int bandwidth;
    AVRational framerate;
    AVStream *assoc_stream; /* demuxer stream associated with this representation */

    int n_fragments;
    struct fragment **fragments; /* VOD list of fragment for profile */

    int n_timelines;
    struct timeline **timelines;

    int64_t first_seq_no;
    int64_t last_seq_no;
    int64_t start_number; /* used in case when we have dynamic list of segment to know which segments are new one*/

    int64_t fragment_duration;
    int64_t fragment_timescale;

    int64_t presentation_timeoffset;

    int64_t cur_seq_no;
    int64_t cur_seg_offset;
    int64_t cur_seg_size;
    struct fragment *cur_seg;

    /* Currently active Media Initialization Section */
    struct fragment *init_section;
    uint8_t *init_sec_buf;
    uint32_t init_sec_buf_size;
    uint32_t init_sec_data_len;
    uint32_t init_sec_buf_read_offset;
    int64_t cur_timestamp;
    int is_restart_needed;
};

static int readFunction(void* opaque, uint8_t* buf, int buf_size) {
    int ret = 0;
    struct DASHContext *v = static_cast<DASHContext *>(opaque);
//    DASHContext *c = static_cast<DASHContext *>(v->parent->priv_data);

//    if (!v->input) {
//        free_fragment(&v->cur_seg);
//        v->cur_seg = get_current_fragment(v);
//        if (!v->cur_seg) {
//            ret = AVERROR_EOF;
//        }
//    }
    return 0;
}

int main(int argc, char *argv[]) {
    char filepath[] = "https://***/stream.mpd";
    representation d = {
    };

    unsigned char *buffer = nullptr;
    const std::shared_ptr<AVIOContext> avioContext(avio_alloc_context(buffer, 8192, 0, &d, &readFunction, nullptr, nullptr), &av_free);
    const auto avFormat = std::shared_ptr<AVFormatContext>(avformat_alloc_context(), &avformat_free_context);

    auto avFormatPtr = avFormat.get();
    avFormatPtr->iformat = av_find_input_format("dash");
    avFormat->pb = avioContext.get();
    auto iFormat = av_find_input_format("dash");
    if (avformat_open_input(&avFormatPtr, filepath, iFormat, NULL) != 0) {
        printf("Couldn't open input stream.\n");
        return -1;
    }
}

The biggest problem with opening it is that: DASH init segment and data segments are encrypted with AES-256. Default DASH demuxer implementation is not able do decode segments on fly so I'm aware that I probably need to rewrite it, but I've no idea how to properly begin reading that stream because now I'm receiving a segfault at readData function. Have you got any idea how could I begin reading from that stream? I've got a key for decrypting that stream.

leandromoreira commented 4 years ago

What I'd recommend is (what you're already aware 🤓 ) to follow along the ffmpeg's dash demuxer source code and try to see where you would add the code and then patch it and build it (or even try to submit it to FFmpeg)

I really don't know if the scenario where you just offer the buffer io (avio) and try to proxy the manifest and decrypt the segments is easier. =/

michalSolarz commented 4 years ago

Hmm, thats the way I would like to follow but I don't know how to use my newly created demuxer code. How could I force ffmpeg to use it? Because for now the only way of overriding something I've found was using custom read_data function. Am I missing something? What is a recommended way of using custom demuxer implementation?

leandromoreira commented 4 years ago

I'm under the impression that if you override the current implementation and build/compile ffmpeg from scratch it'll work.

I think if you plan to add a new demuxer you can inspire yourself by looking in patches how people added (in this case a codec but it looks similar I suppose) or grep with git the addition of a new demuxer.

leandromoreira commented 4 years ago

Here's the addition of dav1d (av1 codec) https://git.ffmpeg.org/gitweb/ffmpeg.git/commitdiff/beaa350e24167f4ff31275a6114693f5ce7cd409 so you might help you

michalSolarz commented 4 years ago

Hi, I've managed to find some nice example of dash player in libdash sources and now I'm following it and reimplementing my own player so I probably won't add it directly in ffmpeg but add decryption after buffering chunk. But thanks for help :)

leandromoreira commented 4 years ago

@madphysicist that's awesome, if you can just share it on github so more people might learn as you did.

madphysicist commented 4 years ago

@leandromoreira I'm assuming you meant @michalSolarz.

michalSolarz commented 4 years ago

@leandromoreira here is a libdash repository: https://github.com/bitmovin/libdash and one day I'll probably create a PR