예제 #1
0
HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(
    IDeckLinkVideoInputFrame *videoFrame, IDeckLinkAudioInputPacket *audioFrame)
{

    frameCount++;

    // Handle Video Frame
    if (videoFrame) {
        BMDTimeValue frameTime;
        BMDTimeValue frameDuration;
        int64_t pts;
        videoFrame->GetStreamTime(&frameTime, &frameDuration,
                                  video_st->time_base.den);

        pts = frameTime / video_st->time_base.num;

        if (initial_video_pts == AV_NOPTS_VALUE) {
            initial_video_pts = pts;
        }

        pts -= initial_video_pts;

        write_video_packet(videoFrame, pts, frameDuration);

        if (serial_fd > 0) {
            char line[8] = {0};
            int count = read(serial_fd, line, 7);
            if (count > 0)
                fprintf(stderr, "read %d bytes: %s  \n", count, line);
            else line[0] = ' ';
            write_data_packet(line, 7, pts);
        }

        if (wallclock) {
            int64_t t = av_gettime();
            char line[20];
            snprintf(line, sizeof(line), "%" PRId64, t);
            write_data_packet(line, strlen(line), pts);
        }
    }

    // Handle Audio Frame
    if (audioFrame)
        write_audio_packet(audioFrame);


    return S_OK;
}
static ngx_int_t ngx_http_mp4frag_handler(ngx_http_request_t *r)
{
    ngx_int_t    rc;
    ngx_chain_t  out;
    u_char *resp_body;
    ngx_buf_t   *resp;
    char *lastslash;
    char *mediafilename;
    u_char *last;
    size_t root;
    ngx_str_t path;
    ngx_str_t index_map = ngx_null_string;
    const u_char *indexptr;
    ngx_str_t mediafile_map = ngx_null_string;
    unsigned medianum, fragnum;
    uint16_t nmedia;
    ngx_str_t videocodecdata, audiocodecdata;
    uint32_t mediaoffset, fragments_offset;
    uint16_t mediafilenamelen;
    uint16_t nsamples, nfragments;
    uint32_t totalsize;
    unsigned int iii;

    if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD))) {
        return NGX_HTTP_NOT_ALLOWED;
    }
 
    /* discard request body, since we don't need it here */
    rc = ngx_http_discard_request_body(r);
 
    if (rc != NGX_OK) {
        return rc;
    }
 
#if 0
    /* set the 'Content-type' header */
    r->headers_out.content_type.len = sizeof("text/html") - 1;
    r->headers_out.content_type.data = (u_char *) "text/html";
#endif
 
    last = ngx_http_map_uri_to_path(r, &path, &root, 0);
    lastslash = strrchr((char*)path.data, '/');
    if ( lastslash ) {
        path.len = lastslash - (char*)path.data;
    }

    /* определить путь к файлу индекса и номер фрагмента: */
    *lastslash++ = 0;
    // uri - dirname, lastslash - basename
    if ( memcmp(lastslash, "Seg1-Frag", 9) != 0 ) {
        return NGX_HTTP_NOT_FOUND;
    }
    fragnum = atoi(lastslash + 9);

    lastslash = strrchr((char*)path.data, '/');
    if ( !lastslash ) {
        return NGX_HTTP_NOT_FOUND;
    }
    medianum = atoi(lastslash + 1);

    memcpy(lastslash + 1, "index", 6);
    
    if ( (rc = make_mapping((const char *)path.data, &index_map, r)) != NGX_OK ) {
        return rc;
    }
    indexptr = index_map.data;

#define CHECKMAP(nbytes) do { if (indexptr + nbytes >= index_map.data + index_map.len) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "index underrun, offset 0x%0x", nbytes); goto GENERAL_ERROR;}  } while(0)

    CHECKMAP(10); /* 8 for signature and 2 for media count */
    if ( memcmp(index_map.data, "mp4frag", 7) != 0 || index_map.data[7] /* version */ > 2 ) {
        free_mapping(&index_map);
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Bad index format in %s", path.data);
        goto GENERAL_ERROR;
    }
    indexptr += 8;

    nmedia = get16(indexptr);
    if ( medianum >= nmedia ) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "No media #%d in %s, total %d media", medianum, path.data, nmedia);
        goto GENERAL_ERROR;
    }
    indexptr += 2;
    CHECKMAP(nmedia * 4);

    mediaoffset = get32(indexptr + medianum * 4);
    if ( mediaoffset >= index_map.len ) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "short index in %s", path.data);
        goto GENERAL_ERROR;
    }
    indexptr = index_map.data;
    CHECKMAP(mediaoffset);
    indexptr = index_map.data + mediaoffset;

    CHECKMAP(2);
    mediafilenamelen = get16(indexptr);
    indexptr += 2;
    CHECKMAP(mediafilenamelen);
    if ( index_map.data[7] == 1 ) {
        if ( (mediafilename = ngx_pcalloc(r->pool, mediafilenamelen + 1)) == NULL ) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Insufficient memory");
            goto GENERAL_ERROR;
        }
        memcpy(mediafilename, (const char *)indexptr, mediafilenamelen);
        mediafilename[mediafilenamelen] = 0;
    }
    else /* index_map.data[7] == 2 */ {
        mediafilename = (char *)indexptr;
    }

    indexptr += mediafilenamelen;
 
    CHECKMAP(2);
    videocodecdata.len = get16(indexptr);
    indexptr += 2;
    CHECKMAP(videocodecdata.len);
    videocodecdata.data = (u_char*)indexptr;
    indexptr += videocodecdata.len;
    CHECKMAP(2);
    audiocodecdata.len = get16(indexptr);
    indexptr += 2;
    CHECKMAP(audiocodecdata.len);
    audiocodecdata.data = (u_char*)indexptr;
    indexptr += audiocodecdata.len;

    /* number of fragments in the media */
    CHECKMAP(2);
    nfragments = get16(indexptr);
    if ( fragnum > nfragments || fragnum < 1 ) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "No fragment #%d in media #%d in file %s", fragnum, medianum, path.data);
        goto NOT_FOUND;
    }
    indexptr += 2;

    CHECKMAP(nfragments * 4);

    fragments_offset = get32(indexptr + (fragnum - 1) * 4);
    indexptr = index_map.data;
    CHECKMAP(fragments_offset);
    indexptr += fragments_offset;

    CHECKMAP(6);  /* first entry should present anyway */
    nsamples = get16(indexptr);
    if ( nsamples < 1 ) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Number of samples is 0 for media #%d, fragment #%d, index %s",
                      medianum, fragnum, path.data);
        goto GENERAL_ERROR;
    }

    /* total fragment size in bytes: */
    totalsize = get32(indexptr + 2);

    ngx_log_error(NGX_LOG_DEBUG, r->connection->log, 0, "nsamples=%d, totalsize=%d", nsamples, totalsize);

    indexptr += 6;

    /* allocate memory for response */
    if ( (resp_body = ngx_pcalloc(r->pool, totalsize)) == NULL ) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Insufficient memory");
        goto GENERAL_ERROR;
    }

    if ( (resp = ngx_pcalloc(r->pool, sizeof(ngx_buf_t))) == NULL ) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "Insufficient memory");
        goto GENERAL_ERROR;
    }
 
    out.buf = resp;
    out.next = NULL;

    resp->pos = resp_body;
    resp->last = resp_body + totalsize;
    resp->memory = 1; 
    resp->last_buf = 1;
 
    if ( make_mapping(mediafilename, &mediafile_map, r) != NGX_OK ) goto GENERAL_ERROR;
 
    /* generate the fragment */
    write32(resp_body, totalsize);
    memcpy(resp_body + 4, "mdat", 4);

    CHECKMAP(16 * nsamples - 1); /* check if the last byte still inside the index */

    /* fragment timestamp is equal to first sample timestamp */
    resp_body = write_fragment_prefix(resp_body + 8, &videocodecdata, &audiocodecdata, get32(indexptr + 8));

    for ( iii = 0; iii < nsamples; ++iii ) {
        uint32_t offset = get32(indexptr);
        uint32_t size = get32(indexptr + 4);
        uint32_t timestamp = get32(indexptr + 8);
        uint32_t composition_offset = get24(indexptr + 12);
        uint8_t flags = indexptr[15];
        indexptr += 16;
        if ( flags ) {
            resp_body = write_video_packet(resp_body, flags & 2, 0, composition_offset, timestamp,
                                     mediafile_map.data + offset, size);
        }
        else {
            resp_body = write_audio_packet(resp_body, 0, timestamp, mediafile_map.data + offset, size);
        }
    }

    free_mapping(&index_map);
    free_mapping(&mediafile_map);

    if ( resp_body != resp->last ) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "response buffer overrun");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->headers_out.status = NGX_HTTP_OK;
    r->headers_out.content_length_n = totalsize;

    rc = ngx_http_send_header(r);
    if (rc == NGX_ERROR || rc > NGX_OK || r->header_only || r->method == NGX_HTTP_HEAD) {
        return rc;
    }

    /* send the buffer chain of your response */
    return ngx_http_output_filter(r, &out);

GENERAL_ERROR:
    free_mapping(&index_map);
    free_mapping(&mediafile_map);
    return NGX_HTTP_INTERNAL_SERVER_ERROR;

NOT_FOUND:
    free_mapping(&index_map);
    free_mapping(&mediafile_map);
    return NGX_HTTP_NOT_FOUND;

}
static u_char *write_fragment_prefix(u_char *buf, ngx_str_t *video, ngx_str_t *audio, uint32_t ts) {
    buf = write_video_packet(buf, 1, 1, 0, ts, (const char *)video->data, video->len);
    return write_audio_packet(buf, 1, ts, (const char *)audio->data, audio->len);
}