Exemple #1
0
static int framemd5_write_header(struct AVFormatContext *s)
{
    struct MD5Context *c = s->priv_data;
    c->md5 = av_md5_alloc();
    if (!c->md5)
        return AVERROR(ENOMEM);
    return ff_framehash_write_header(s);
}
Exemple #2
0
static int write_header(struct AVFormatContext *s)
{
    struct MD5Context *c = s->priv_data;
    c->md5 = av_md5_alloc();
    if (!c->md5)
        return AVERROR(ENOMEM);
    av_md5_init(c->md5);
    return 0;
}
static int md5_open(URLContext *h, const char *filename, int flags)
{
    struct MD5Context *c = h->priv_data;

    if (!(flags & AVIO_FLAG_WRITE))
        return AVERROR(EINVAL);

    c->md5 = av_md5_alloc();
    if (!c->md5)
        return AVERROR(ENOMEM);
    av_md5_init(c->md5);

    return 0;
}
Exemple #4
0
/* Generate a digest reply, according to RFC 2617. */
static char *make_digest_auth(HTTPAuthState *state, const char *username,
                              const char *password, const char *uri,
                              const char *method)
{
    DigestParams *digest = &state->digest_params;
    int len;
    uint32_t cnonce_buf[2];
    char cnonce[17];
    char nc[9];
    int i;
    char A1hash[33], A2hash[33], response[33];
    struct AVMD5 *md5ctx;
    uint8_t hash[16];
    char *authstr;

    digest->nc++;
    snprintf(nc, sizeof(nc), "%08x", digest->nc);

    /* Generate a client nonce. */
    for (i = 0; i < 2; i++)
        cnonce_buf[i] = av_get_random_seed();
    ff_data_to_hex(cnonce, (const uint8_t*) cnonce_buf, sizeof(cnonce_buf), 1);
    cnonce[2*sizeof(cnonce_buf)] = 0;

    md5ctx = av_md5_alloc();
    if (!md5ctx)
        return NULL;

    av_md5_init(md5ctx);
    update_md5_strings(md5ctx, username, ":", state->realm, ":", password, NULL);
    av_md5_final(md5ctx, hash);
    ff_data_to_hex(A1hash, hash, 16, 1);
    A1hash[32] = 0;

    if (!strcmp(digest->algorithm, "") || !strcmp(digest->algorithm, "MD5")) {
    } else if (!strcmp(digest->algorithm, "MD5-sess")) {
        av_md5_init(md5ctx);
        update_md5_strings(md5ctx, A1hash, ":", digest->nonce, ":", cnonce, NULL);
        av_md5_final(md5ctx, hash);
        ff_data_to_hex(A1hash, hash, 16, 1);
        A1hash[32] = 0;
    } else {
        /* Unsupported algorithm */
        av_free(md5ctx);
        return NULL;
    }

    av_md5_init(md5ctx);
    update_md5_strings(md5ctx, method, ":", uri, NULL);
    av_md5_final(md5ctx, hash);
    ff_data_to_hex(A2hash, hash, 16, 1);
    A2hash[32] = 0;

    av_md5_init(md5ctx);
    update_md5_strings(md5ctx, A1hash, ":", digest->nonce, NULL);
    if (!strcmp(digest->qop, "auth") || !strcmp(digest->qop, "auth-int")) {
        update_md5_strings(md5ctx, ":", nc, ":", cnonce, ":", digest->qop, NULL);
    }
    update_md5_strings(md5ctx, ":", A2hash, NULL);
    av_md5_final(md5ctx, hash);
    ff_data_to_hex(response, hash, 16, 1);
    response[32] = 0;

    av_free(md5ctx);

    if (!strcmp(digest->qop, "") || !strcmp(digest->qop, "auth")) {
    } else if (!strcmp(digest->qop, "auth-int")) {
        /* qop=auth-int not supported */
        return NULL;
    } else {
        /* Unsupported qop value. */
        return NULL;
    }

    len = strlen(username) + strlen(state->realm) + strlen(digest->nonce) +
              strlen(uri) + strlen(response) + strlen(digest->algorithm) +
              strlen(digest->opaque) + strlen(digest->qop) + strlen(cnonce) +
              strlen(nc) + 150;

    authstr = av_malloc(len);
    if (!authstr)
        return NULL;
    snprintf(authstr, len, "Authorization: Digest ");

    /* TODO: Escape the quoted strings properly. */
    av_strlcatf(authstr, len, "username=\"%s\"",   username);
    av_strlcatf(authstr, len, ", realm=\"%s\"",     state->realm);
    av_strlcatf(authstr, len, ", nonce=\"%s\"",     digest->nonce);
    av_strlcatf(authstr, len, ", uri=\"%s\"",       uri);
    av_strlcatf(authstr, len, ", response=\"%s\"",  response);

    if (digest->algorithm[0])
        av_strlcatf(authstr, len, ", algorithm=%s",  digest->algorithm);
    if (digest->opaque[0])
        av_strlcatf(authstr, len, ", opaque=\"%s\"", digest->opaque);
    if (digest->qop[0]) {
        av_strlcatf(authstr, len, ", qop=\"%s\"",    digest->qop);
        av_strlcatf(authstr, len, ", cnonce=\"%s\"", cnonce);
        av_strlcatf(authstr, len, ", nc=%s",         nc);
    }

    av_strlcatf(authstr, len, "\r\n");

    return authstr;
}
Exemple #5
0
int main(int argc, char **argv)
{
    int c;
    uint8_t header[HASH_SIZE];
    uint8_t content[HASH_SIZE];
    int empty_moov_pos;
    int prev_pos;

    for (;;) {
        c = getopt(argc, argv, "wh");
        if (c == -1)
            break;
        switch (c) {
        case 'w':
            write_file = 1;
            break;
        default:
        case 'h':
            help();
            return 0;
        }
    }

    av_register_all();

    md5 = av_md5_alloc();
    if (!md5)
        return 1;

    // Write a fragmented file with an initial moov that actually contains some
    // samples. One moov+mdat with 1 second of data and one moof+mdat with 1
    // second of data.
    init_out("non-empty-moov");
    av_dict_set(&opts, "movflags", "frag_keyframe", 0);
    init(0, 0);
    mux_gops(2);
    finish();
    close_out();

    // Write a similar file, but with b-frames and audio preroll, handled
    // via an edit list.
    init_out("non-empty-moov-elst");
    av_dict_set(&opts, "movflags", "frag_keyframe", 0);
    av_dict_set(&opts, "use_editlist", "1", 0);
    init(1, 1);
    mux_gops(2);
    finish();
    close_out();

    // Use b-frames but no audio-preroll, but without an edit list.
    // Due to avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO, the dts
    // of the first audio packet is > 0, but it is set to zero since edit
    // lists aren't used, increasing the duration of the first packet instead.
    init_out("non-empty-moov-no-elst");
    av_dict_set(&opts, "movflags", "frag_keyframe", 0);
    av_dict_set(&opts, "use_editlist", "0", 0);
    init(1, 0);
    mux_gops(2);
    finish();
    close_out();

    format = "ismv";
    // Write an ISMV, with b-frames and audio preroll.
    init_out("ismv");
    av_dict_set(&opts, "movflags", "frag_keyframe", 0);
    init(1, 1);
    mux_gops(2);
    finish();
    close_out();
    format = "mp4";

    // An initial moov that doesn't contain any samples, followed by two
    // moof+mdat pairs.
    init_out("empty-moov");
    av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
    av_dict_set(&opts, "use_editlist", "0", 0);
    init(0, 0);
    mux_gops(2);
    finish();
    close_out();
    memcpy(content, hash, HASH_SIZE);

    // Similar to the previous one, but with input that doesn't start at
    // pts/dts 0. avoid_negative_ts behaves in the same way as
    // in non-empty-moov-no-elst above.
    init_out("empty-moov-no-elst");
    av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
    init(1, 0);
    mux_gops(2);
    finish();
    close_out();

    // Same as the previous one, but disable avoid_negative_ts (which
    // would require using an edit list, but with empty_moov, one can't
    // write a sensible edit list, when the start timestamps aren't known).
    // This should trigger a warning - we check that the warning is produced.
    init_count_warnings();
    init_out("empty-moov-no-elst-no-adjust");
    av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
    av_dict_set(&opts, "avoid_negative_ts", "0", 0);
    init(1, 0);
    mux_gops(2);
    finish();
    close_out();

    reset_count_warnings();
    check(num_warnings > 0, "No warnings printed for unhandled start offset");

    // Verify that delay_moov produces the same as empty_moov for
    // simple input
    init_out("delay-moov");
    av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
    av_dict_set(&opts, "use_editlist", "0", 0);
    init(0, 0);
    mux_gops(2);
    finish();
    close_out();
    check(!memcmp(hash, content, HASH_SIZE), "delay_moov differs from empty_moov");

    // Test writing content that requires an edit list using delay_moov
    init_out("delay-moov-elst");
    av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
    init(1, 1);
    mux_gops(2);
    finish();
    close_out();

    // Test writing a file with one track lacking packets, with delay_moov.
    skip_write_audio = 1;
    init_out("delay-moov-empty-track");
    av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov", 0);
    init(0, 0);
    mux_gops(2);
    // The automatic flushing shouldn't output anything, since we're still
    // waiting for data for some tracks
    check(out_size == 0, "delay_moov flushed prematurely");
    // When closed (or manually flushed), all the written data should still
    // be output.
    finish();
    close_out();
    check(out_size > 0, "delay_moov didn't output anything");

    // Check that manually flushing still outputs things as expected. This
    // produces two fragments, while the one above produces only one.
    init_out("delay-moov-empty-track-flush");
    av_dict_set(&opts, "movflags", "frag_custom+delay_moov", 0);
    init(0, 0);
    mux_gops(1);
    av_write_frame(ctx, NULL); // Force writing the moov
    check(out_size > 0, "No moov written");
    av_write_frame(ctx, NULL);
    mux_gops(1);
    av_write_frame(ctx, NULL);
    finish();
    close_out();

    skip_write_audio = 0;



    // Verify that the header written by delay_moov when manually flushed
    // is identical to the one by empty_moov.
    init_out("empty-moov-header");
    av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
    av_dict_set(&opts, "use_editlist", "0", 0);
    init(0, 0);
    close_out();
    memcpy(header, hash, HASH_SIZE);
    init_out("empty-moov-content");
    mux_gops(2);
    // Written 2 seconds of content, with an automatic flush after 1 second.
    check(out_size > 0, "No automatic flush?");
    empty_moov_pos = prev_pos = out_size;
    // Manually flush the second fragment
    av_write_frame(ctx, NULL);
    check(out_size > prev_pos, "No second fragment flushed?");
    prev_pos = out_size;
    // Check that an extra flush doesn't output any more data
    av_write_frame(ctx, NULL);
    check(out_size == prev_pos, "More data written?");
    close_out();
    memcpy(content, hash, HASH_SIZE);
    // Ignore the trailer written here
    finish();

    init_out("delay-moov-header");
    av_dict_set(&opts, "movflags", "frag_custom+delay_moov", 0);
    av_dict_set(&opts, "use_editlist", "0", 0);
    init(0, 0);
    check(out_size == 0, "Output written during init with delay_moov");
    mux_gops(1); // Write 1 second of content
    av_write_frame(ctx, NULL); // Force writing the moov
    close_out();
    check(!memcmp(hash, header, HASH_SIZE), "delay_moov header differs from empty_moov");
    init_out("delay-moov-content");
    av_write_frame(ctx, NULL); // Flush the first fragment
    check(out_size == empty_moov_pos, "Manually flushed content differs from automatically flushed, %d vs %d", out_size, empty_moov_pos);
    mux_gops(1); // Write the rest of the content
    av_write_frame(ctx, NULL); // Flush the second fragment
    close_out();
    check(!memcmp(hash, content, HASH_SIZE), "delay_moov content differs from empty_moov");
    finish();


    // Verify that we can produce an identical second fragment without
    // writing the first one. First write the reference fragments that
    // we want to reproduce.
    av_dict_set(&opts, "movflags", "frag_custom+empty_moov+dash", 0);
    init(0, 0);
    mux_gops(1);
    av_write_frame(ctx, NULL); // Output the first fragment
    init_out("empty-moov-second-frag");
    mux_gops(1);
    av_write_frame(ctx, NULL); // Output the second fragment
    close_out();
    memcpy(content, hash, HASH_SIZE);
    finish();

    // Produce the same second fragment without actually writing the first
    // one before.
    av_dict_set(&opts, "movflags", "frag_custom+empty_moov+dash+frag_discont", 0);
    av_dict_set(&opts, "fragment_index", "2", 0);
    av_dict_set(&opts, "avoid_negative_ts", "0", 0);
    av_dict_set(&opts, "use_editlist", "0", 0);
    init(0, 0);
    skip_gops(1);
    init_out("empty-moov-second-frag-discont");
    mux_gops(1);
    av_write_frame(ctx, NULL); // Output the second fragment
    close_out();
    check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
    finish();

    // Produce the same thing by using delay_moov, which requires a slightly
    // different call sequence.
    av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash+frag_discont", 0);
    av_dict_set(&opts, "fragment_index", "2", 0);
    init(0, 0);
    skip_gops(1);
    mux_gops(1);
    av_write_frame(ctx, NULL); // Output the moov
    init_out("delay-moov-second-frag-discont");
    av_write_frame(ctx, NULL); // Output the second fragment
    close_out();
    check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
    finish();


    // Test discontinously written fragments with b-frames (where the
    // assumption of starting at pts=0 works) but not with audio preroll
    // (which can't be guessed).
    av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash", 0);
    init(1, 0);
    mux_gops(1);
    init_out("delay-moov-elst-init");
    av_write_frame(ctx, NULL); // Output the moov
    close_out();
    memcpy(header, hash, HASH_SIZE);
    av_write_frame(ctx, NULL); // Output the first fragment
    init_out("delay-moov-elst-second-frag");
    mux_gops(1);
    av_write_frame(ctx, NULL); // Output the second fragment
    close_out();
    memcpy(content, hash, HASH_SIZE);
    finish();

    av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash+frag_discont", 0);
    av_dict_set(&opts, "fragment_index", "2", 0);
    init(1, 0);
    skip_gops(1);
    mux_gops(1); // Write the second fragment
    init_out("delay-moov-elst-init-discont");
    av_write_frame(ctx, NULL); // Output the moov
    close_out();
    check(!memcmp(hash, header, HASH_SIZE), "discontinuously written header differs");
    init_out("delay-moov-elst-second-frag-discont");
    av_write_frame(ctx, NULL); // Output the second fragment
    close_out();
    check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
    finish();


    // Test discontinously written fragments with b-frames and audio preroll,
    // properly signaled.
    av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash", 0);
    init(1, 1);
    mux_gops(1);
    init_out("delay-moov-elst-signal-init");
    av_write_frame(ctx, NULL); // Output the moov
    close_out();
    memcpy(header, hash, HASH_SIZE);
    av_write_frame(ctx, NULL); // Output the first fragment
    init_out("delay-moov-elst-signal-second-frag");
    mux_gops(1);
    av_write_frame(ctx, NULL); // Output the second fragment
    close_out();
    memcpy(content, hash, HASH_SIZE);
    finish();

    av_dict_set(&opts, "movflags", "frag_custom+delay_moov+dash+frag_discont", 0);
    av_dict_set(&opts, "fragment_index", "2", 0);
    init(1, 1);
    signal_init_ts();
    skip_gops(1);
    mux_gops(1); // Write the second fragment
    init_out("delay-moov-elst-signal-init-discont");
    av_write_frame(ctx, NULL); // Output the moov
    close_out();
    check(!memcmp(hash, header, HASH_SIZE), "discontinuously written header differs");
    init_out("delay-moov-elst-signal-second-frag-discont");
    av_write_frame(ctx, NULL); // Output the second fragment
    close_out();
    check(!memcmp(hash, content, HASH_SIZE), "discontinuously written fragment differs");
    finish();


    // Test VFR content, with sidx atoms (which declare the pts duration
    // of a fragment, forcing overriding the start pts of the next one).
    // Here, the fragment duration in pts is significantly different from
    // the duration in dts. The video stream starts at dts=-10,pts=0, and
    // the second fragment starts at dts=155,pts=156. The trun duration sum
    // of the first fragment is 165, which also is written as
    // baseMediaDecodeTime in the tfdt in the second fragment. The sidx for
    // the first fragment says earliest_presentation_time = 0 and
    // subsegment_duration = 156, which also matches the sidx in the second
    // fragment. For the audio stream, the pts and dts durations also don't
    // match - the input stream starts at pts=-2048, but that part is excluded
    // by the edit list.
    init_out("vfr");
    av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov+dash", 0);
    init_fps(1, 1, 3);
    mux_frames(gop_size/2);
    duration /= 10;
    mux_frames(gop_size/2);
    mux_gops(1);
    finish();
    close_out();

    // Test VFR content, with cleared duration fields. In these cases,
    // the muxer must guess the duration of the last packet of each
    // fragment. As long as the framerate doesn't vary (too much) at the
    // fragment edge, it works just fine. Additionally, when automatically
    // cutting fragments, the muxer already know the timestamps of the next
    // packet for one stream (in most cases the video stream), avoiding
    // having to use guesses for that one.
    init_count_warnings();
    clear_duration = 1;
    init_out("vfr-noduration");
    av_dict_set(&opts, "movflags", "frag_keyframe+delay_moov+dash", 0);
    init_fps(1, 1, 3);
    mux_frames(gop_size/2);
    duration /= 10;
    mux_frames(gop_size/2);
    mux_gops(1);
    finish();
    close_out();
    clear_duration = 0;
    reset_count_warnings();
    check(num_warnings > 0, "No warnings printed for filled in durations");

    av_free(md5);

    return check_faults > 0 ? 1 : 0;
}
Exemple #6
0
int main(int argc, char *argv[])
{
    struct AVMD5 *md5;
    AVFilterGraph *graph;
    AVFilterContext *src, *sink;
    AVFrame *frame;
    uint8_t errstr[1024];
    float duration;
    int err, nb_frames, i;

    if (argc < 2) {
        fprintf(stderr, "Usage: %s <duration>\n", argv[0]);
        return 1;
    }

    duration  = atof(argv[1]);
    nb_frames = duration * INPUT_SAMPLERATE / FRAME_SIZE;
    if (nb_frames <= 0) {
        fprintf(stderr, "Invalid duration: %s\n", argv[1]);
        return 1;
    }

    avfilter_register_all();

    /* Allocate the frame we will be using to store the data. */
    frame  = av_frame_alloc();
    if (!frame) {
        fprintf(stderr, "Error allocating the frame\n");
        return 1;
    }

    md5 = av_md5_alloc();
    if (!md5) {
        fprintf(stderr, "Error allocating the MD5 context\n");
        return 1;
    }

    /* Set up the filtergraph. */
    err = init_filter_graph(&graph, &src, &sink);
    if (err < 0) {
        fprintf(stderr, "Unable to init filter graph:");
        goto fail;
    }

    /* the main filtering loop */
    for (i = 0; i < nb_frames; i++) {
        /* get an input frame to be filtered */
        err = get_input(frame, i);
        if (err < 0) {
            fprintf(stderr, "Error generating input frame:");
            goto fail;
        }

        /* Send the frame to the input of the filtergraph. */
        err = av_buffersrc_add_frame(src, frame);
        if (err < 0) {
            av_frame_unref(frame);
            fprintf(stderr, "Error submitting the frame to the filtergraph:");
            goto fail;
        }

        /* Get all the filtered output that is available. */
        while ((err = av_buffersink_get_frame(sink, frame)) >= 0) {
            /* now do something with our filtered frame */
            err = process_output(md5, frame);
            if (err < 0) {
                fprintf(stderr, "Error processing the filtered frame:");
                goto fail;
            }
            av_frame_unref(frame);
        }

        if (err == AVERROR(EAGAIN)) {
            /* Need to feed more frames in. */
            continue;
        } else if (err == AVERROR_EOF) {
            /* Nothing more to do, finish. */
            break;
        } else if (err < 0) {
            /* An error occurred. */
            fprintf(stderr, "Error filtering the data:");
            goto fail;
        }
    }

    avfilter_graph_free(&graph);
    av_frame_free(&frame);
    av_freep(&md5);

    return 0;

fail:
    av_strerror(err, errstr, sizeof(errstr));
    fprintf(stderr, "%s\n", errstr);
    return 1;
}