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); }