void ds_free_packs(demux_stream_t *ds) { demux_packet_t *dp = ds->first; while (dp) { demux_packet_t *dn = dp->next; free_demux_packet(dp); dp = dn; } if (ds->asf_packet) { // free unfinished .asf fragments: free(ds->asf_packet->buffer); free(ds->asf_packet); ds->asf_packet = NULL; } ds->first = ds->last = NULL; ds->packs = 0; // !!!!! ds->bytes = 0; if (ds->current) free_demux_packet(ds->current); ds->current = NULL; ds->buffer = NULL; ds->buffer_pos = ds->buffer_size; ds->pts = MP_NOPTS_VALUE; ds->pts_bytes = 0; }
// return value: // 0 = EOF or no stream found // 1 = successfully read a packet static int demux_mf_fill_buffer(demuxer_t *demuxer, demux_stream_t *ds){ mf_t * mf = demuxer->priv; struct stat fs; FILE * f; if ( mf->curr_frame >= mf->nr_of_files ) return 0; stat( mf->names[mf->curr_frame],&fs ); // printf( "[demux_mf] frame: %d (%s,%d)\n",mf->curr_frame,mf->names[mf->curr_frame],fs.st_size ); if ( !( f=fopen( mf->names[mf->curr_frame],"rb" ) ) ) return 0; { sh_video_t * sh_video = demuxer->video->sh; demux_packet_t * dp = new_demux_packet( fs.st_size ); if ( !fread( dp->buffer,fs.st_size,1,f ) ) { fclose(f); free_demux_packet(dp); return 0; } dp->pts=mf->curr_frame / sh_video->fps; dp->pos=mf->curr_frame; dp->flags=1; // append packet to DS stream: ds_add_packet( demuxer->video,dp ); } fclose( f ); demuxer->filepos=mf->curr_frame++; return 1; }
ReadBufferQueue::~ReadBufferQueue() { free((void *)fTag); // Free any pending buffers (that never got delivered): demux_packet_t* dp = pendingDPHead; while (dp != NULL) { demux_packet_t* dpNext = dp->next; dp->next = NULL; free_demux_packet(dp); dp = dpNext; } }
void free_demux_packet(struct demux_packet *dp) { if (dp->master == NULL) { //dp is a master packet dp->refcount--; if (dp->refcount == 0) { if (dp->avpacket) talloc_free(dp->avpacket); else free(dp->buffer); free(dp); } return; } // dp is a clone: free_demux_packet(dp->master); free(dp); }
extern "C" int demux_rtp_fill_buffer(demuxer_t* demuxer, demux_stream_t* ds) { // Get a filled-in "demux_packet" from the RTP source, and deliver it. // Note that this is called as a synchronous read operation, so it needs // to block in the (hopefully infrequent) case where no packet is // immediately available. while (1) { float ptsBehind; demux_packet_t* dp = getBuffer(demuxer, ds, False, ptsBehind); // blocking if (dp == NULL) return 0; if (demuxer->stream->eof) return 0; // source stream has closed down // Before using this packet, check to make sure that its presentation // time is not far behind the other stream (if any). If it is, // then we discard this packet, and get another instead. (The rest of // MPlayer doesn't always do a good job of synchronizing when the // audio and video streams get this far apart.) // (We don't do this when streaming over TCP, because then the audio and // video streams are interleaved.) // (Also, if the stream is *excessively* far behind, then we allow // the packet, because in this case it probably means that there was // an error in the source's timestamp synchronization.) const float ptsBehindThreshold = 1.0; // seconds const float ptsBehindLimit = 60.0; // seconds if (ptsBehind < ptsBehindThreshold || ptsBehind > ptsBehindLimit || rtsp_transport_tcp) { // packet's OK ds_add_packet(ds, dp); break; } #ifdef DEBUG_PRINT_DISCARDED_PACKETS RTPState* rtpState = (RTPState*)(demuxer->priv); ReadBufferQueue* bufferQueue = ds == demuxer->video ? rtpState->videoBufferQueue : rtpState->audioBufferQueue; fprintf(stderr, "Discarding %s packet (%fs behind)\n", bufferQueue->tag(), ptsBehind); #endif free_demux_packet(dp); // give back this packet, and get another one } return 1; }
static demux_packet_t* getBuffer(demuxer_t* demuxer, demux_stream_t* ds, Boolean mustGetNewData, float& ptsBehind) { // Begin by finding the buffer queue that we want to read from: // (Get this from the RTP state, which we stored in // the demuxer's 'priv' field) RTPState* rtpState = (RTPState*)(demuxer->priv); ReadBufferQueue* bufferQueue = NULL; int headersize = 0; TaskToken task; if (demuxer->stream->eof) return NULL; if (ds == demuxer->video) { bufferQueue = rtpState->videoBufferQueue; if (((sh_video_t*)ds->sh)->format == mmioFOURCC('H','2','6','4')) headersize = 3; } else if (ds == demuxer->audio) { bufferQueue = rtpState->audioBufferQueue; if (bufferQueue->readSource()->isAMRAudioSource()) headersize = 1; } else { fprintf(stderr, "(demux_rtp)getBuffer: internal error: unknown stream\n"); return NULL; } if (bufferQueue == NULL || bufferQueue->readSource() == NULL) { fprintf(stderr, "(demux_rtp)getBuffer failed: no appropriate RTP subsession has been set up\n"); return NULL; } demux_packet_t* dp = NULL; if (!mustGetNewData) { // Check whether we have a previously-saved buffer that we can use: dp = bufferQueue->getPendingBuffer(); if (dp != NULL) { ptsBehind = 0.0; // so that we always accept this data return dp; } } // Allocate a new packet buffer, and arrange to read into it: if (!bufferQueue->nextpacket) { dp = new_demux_packet(MAX_RTP_FRAME_SIZE); bufferQueue->dp = dp; if (dp == NULL) return NULL; } #ifdef CONFIG_LIBAVCODEC extern AVCodecParserContext * h264parserctx; int consumed, poutbuf_size = 1; const uint8_t *poutbuf = NULL; float lastpts = 0.0; do { if (!bufferQueue->nextpacket) { #endif // Schedule the read operation: bufferQueue->blockingFlag = 0; bufferQueue->readSource()->getNextFrame(&dp->buffer[headersize], MAX_RTP_FRAME_SIZE - headersize, afterReading, bufferQueue, onSourceClosure, bufferQueue); // Block ourselves until data becomes available: TaskScheduler& scheduler = bufferQueue->readSource()->envir().taskScheduler(); int delay = 10000000; if (bufferQueue->prevPacketPTS * 1.05 > rtpState->mediaSession->playEndTime()) delay /= 10; task = scheduler.scheduleDelayedTask(delay, onSourceClosure, bufferQueue); scheduler.doEventLoop(&bufferQueue->blockingFlag); scheduler.unscheduleDelayedTask(task); if (demuxer->stream->eof) { free_demux_packet(dp); return NULL; } if (headersize == 1) // amr dp->buffer[0] = ((AMRAudioSource*)bufferQueue->readSource())->lastFrameHeader(); #ifdef CONFIG_LIBAVCODEC } else { bufferQueue->dp = dp = bufferQueue->nextpacket; bufferQueue->nextpacket = NULL; } if (headersize == 3 && h264parserctx) { // h264 consumed = h264parserctx->parser->parser_parse(h264parserctx, avcctx, &poutbuf, &poutbuf_size, dp->buffer, dp->len); if (!consumed && !poutbuf_size) return NULL; if (!poutbuf_size) { lastpts=dp->pts; free_demux_packet(dp); bufferQueue->dp = dp = new_demux_packet(MAX_RTP_FRAME_SIZE); } else { bufferQueue->nextpacket = dp; bufferQueue->dp = dp = new_demux_packet(poutbuf_size); memcpy(dp->buffer, poutbuf, poutbuf_size); dp->pts=lastpts; } } } while (!poutbuf_size); #endif // Set the "ptsBehind" result parameter: if (bufferQueue->prevPacketPTS != 0.0 && bufferQueue->prevPacketWasSynchronized && *(bufferQueue->otherQueue) != NULL && (*(bufferQueue->otherQueue))->prevPacketPTS != 0.0 && (*(bufferQueue->otherQueue))->prevPacketWasSynchronized) { ptsBehind = (*(bufferQueue->otherQueue))->prevPacketPTS - bufferQueue->prevPacketPTS; } else { ptsBehind = 0.0; } if (mustGetNewData) { // Save this buffer for future reads: bufferQueue->savePendingBuffer(dp); } return dp; }
void ASFGenerateParcel(Context_t *context, const demuxer_t *demuxer) { demux_stream_t *video = demuxer->video; demux_stream_t *audio = demuxer->audio; unsigned long long int Pts = 0; //printf("P\n"); if (audio->first != NULL) { //printf("A\n"); demux_packet_t *current = audio->first; //printf("PTS: %f\n", current->pts); Pts = (current->pts * 90000); while (current != NULL) { context->output->audio->Write(context, current->buffer, current->len, Pts, STREAMHEADERBUFFER, STREAMHEADERBUFFERSIZE, 0, "audio"); demux_packet_t *dn = current->next; free_demux_packet(current); current = dn; //current = current->next; Pts = INVALID_PTS_VALUE; } audio->first = audio->last = NULL; audio->packs = 0; // !!!!! audio->bytes = 0; if (audio->current) free_demux_packet(audio->current); audio->current = NULL; audio->buffer = NULL; audio->buffer_pos = audio->buffer_size; audio->pts = 0; audio->pts_bytes = 0; } if (video->first != NULL) { //printf("V\n"); demux_packet_t *current = video->first; //if (!(current->flags&0x10)) { //current frame isn't a keyframe //printf("\tNORMALFRAME, "); // Pts = INVALID_PTS_VALUE; //} else { // //printf("\tKEYFRAME, "); // Pts = (current->pts * 90000); //} while (current != NULL) { Pts = (current->pts * 90000); //printf("PTS: %f (%u)\n", current->pts, Pts); sh_video = demuxer->video->sh; sh_video->ds = demuxer->video; bwmv_t *priv = (bwmv_t *)malloc(sizeof(bwmv_t)); memcpy(priv->privateData, ASF_PRIVATE_DATA, 4); priv->width = sh_video->bih->biWidth; priv->height = sh_video->bih->biHeight; priv->framerate = 333667; context->output->video->Write(context, current->buffer, current->len, Pts, (unsigned char *) priv, sizeof(bwmv_t), 0, "video"); free(priv); demux_packet_t *dn = current->next; free_demux_packet(current); current = dn; //current = current->next; //Pts = INVALID_PTS_VALUE; } video->first = video->last = NULL; video->packs = 0; // !!!!! video->bytes = 0; if (video->current) free_demux_packet(video->current); video->current = NULL; video->buffer = NULL; video->buffer_pos = video->buffer_size; video->pts = 0; video->pts_bytes = 0; } }
// return value: // 0 = EOF // 1 = successful int ds_fill_buffer(demux_stream_t *ds) { demuxer_t *demux = ds->demuxer; if (ds->current) free_demux_packet(ds->current); ds->current = NULL; mp_dbg(MSGT_DEMUXER, MSGL_DBG3, "ds_fill_buffer (%s) called\n", ds == demux->audio ? "d_audio" : ds == demux->video ? "d_video" : ds == demux->sub ? "d_sub" : "unknown"); while (1) { if (ds->packs) { demux_packet_t *p = ds->first; // copy useful data: ds->buffer = p->buffer; ds->buffer_pos = 0; ds->buffer_size = p->len; ds->pos = p->pos; ds->dpos += p->len; // !!! ++ds->pack_no; if (p->pts != MP_NOPTS_VALUE) { ds->pts = p->pts; ds->pts_bytes = 0; } ds->pts_bytes += p->len; // !!! if (p->stream_pts != MP_NOPTS_VALUE) demux->stream_pts = p->stream_pts; ds->keyframe = p->keyframe; // unlink packet: ds->bytes -= p->len; ds->current = p; ds->first = p->next; if (!ds->first) ds->last = NULL; --ds->packs; /* The code below can set ds->eof to 1 when another stream runs * out of buffer space. That makes sense because in that situation * the calling code should not count on being able to demux more * packets from this stream. * If however the situation improves and we're called again * despite the eof flag then it's better to clear it to avoid * weird behavior. */ ds->eof = 0; return 1; } #define MaybeNI _("Maybe you are playing a non-interleaved stream/file or the codec failed?\n" \ "For AVI files, try to force non-interleaved mode with the -ni option.\n") if (demux->audio->packs >= MAX_PACKS || demux->audio->bytes >= MAX_PACK_BYTES) { mp_tmsg(MSGT_DEMUXER, MSGL_ERR, "\nToo many audio packets in the buffer: (%d in %d bytes).\n", demux->audio->packs, demux->audio->bytes); mp_tmsg(MSGT_DEMUXER, MSGL_HINT, MaybeNI); break; } if (demux->video->packs >= MAX_PACKS || demux->video->bytes >= MAX_PACK_BYTES) { mp_tmsg(MSGT_DEMUXER, MSGL_ERR, "\nToo many video packets in the buffer: (%d in %d bytes).\n", demux->video->packs, demux->video->bytes); mp_tmsg(MSGT_DEMUXER, MSGL_HINT, MaybeNI); break; } if (!demux_fill_buffer(demux, ds)) { mp_dbg(MSGT_DEMUXER, MSGL_DBG2, "ds_fill_buffer()->demux_fill_buffer() failed\n"); break; // EOF } } ds->buffer_pos = ds->buffer_size = 0; ds->buffer = NULL; mp_msg(MSGT_DEMUXER, MSGL_V, "ds_fill_buffer: EOF reached (stream: %s) \n", ds == demux->audio ? "audio" : "video"); ds->eof = 1; return 0; }