changeset 6192:f03fe2e84efd

clone_demux_packet(), using refcounting to avoid memcpy() based on (sligtly simplified) patch by Alexander Neundorf <neundorf@dellingsoft.de>
author arpi
date Sat, 25 May 2002 22:13:23 +0000
parents 26a980dbc9a5
children 2fd9ec444098
files libmpdemux/demuxer.c libmpdemux/demuxer.h
diffstat 2 files changed, 35 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/libmpdemux/demuxer.c	Sat May 25 21:43:02 2002 +0000
+++ b/libmpdemux/demuxer.c	Sat May 25 22:13:23 2002 +0000
@@ -38,7 +38,7 @@
 //---------------
   ds->packs=0;
   ds->bytes=0;
-  ds->first=ds->last=NULL;
+  ds->first=ds->last=ds->current=NULL;
   ds->id=id;
   ds->demuxer=demuxer;
 //----------------
@@ -296,7 +296,7 @@
 //     1 = succesfull
 int ds_fill_buffer(demux_stream_t *ds){
   demuxer_t *demux=ds->demuxer;
-  if(ds->buffer) free(ds->buffer);
+  if(ds->current) free_demux_packet(ds->current);
   if(verbose>2){
     if(ds==demux->audio) mp_dbg(MSGT_DEMUXER,MSGL_DBG3,"ds_fill_buffer(d_audio) called\n");else
     if(ds==demux->video) mp_dbg(MSGT_DEMUXER,MSGL_DBG3,"ds_fill_buffer(d_video) called\n");else
@@ -319,11 +319,11 @@
       }
       ds->pts_bytes+=p->len; // !!!
       ds->flags=p->flags;
-      // free packet:
+      // unlink packet:
       ds->bytes-=p->len;
+      ds->current=p;
       ds->first=p->next;
       if(!ds->first) ds->last=NULL;
-      free(p);
       --ds->packs;
       return 1; //ds->buffer_size;
     }
@@ -344,6 +344,7 @@
   }
   ds->buffer_pos=ds->buffer_size=0;
   ds->buffer=NULL;
+  ds->current=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;
@@ -387,8 +388,7 @@
   demux_packet_t *dp=ds->first;
   while(dp){
     demux_packet_t *dn=dp->next;
-    if(dp->buffer) free(dp->buffer);
-    free(dp);
+    free_demux_packet(dp);
     dp=dn;
   }
   if(ds->asf_packet){
@@ -400,7 +400,8 @@
   ds->first=ds->last=NULL;
   ds->packs=0; // !!!!!
   ds->bytes=0;
-  if(ds->buffer) free(ds->buffer);
+  if(ds->current) free_demux_packet(ds->current);
+  ds->current=NULL;
   ds->buffer=NULL;
   ds->buffer_pos=ds->buffer_size;
   ds->pts=0; ds->pts_bytes=0;
--- a/libmpdemux/demuxer.h	Sat May 25 21:43:02 2002 +0000
+++ b/libmpdemux/demuxer.h	Sat May 25 22:13:23 2002 +0000
@@ -51,13 +51,15 @@
   off_t pos;  // position in index (AVI) or file (MPG)
   unsigned char* buffer;
   int flags; // keyframe, etc
+  int refcount;   //refcounter for the master packet, if 0, buffer can be free()d
+  struct demux_packet_st* master; //pointer to the master packet if this one is a cloned one
   struct demux_packet_st* next;
 } demux_packet_t;
 
 typedef struct {
   int buffer_pos;          // current buffer position
   int buffer_size;         // current buffer size
-  unsigned char* buffer;   // current buffer
+  unsigned char* buffer;   // current buffer, never free() it, always use free_demux_packet(buffer_ref);
   float pts;               // current buffer's pts
   int pts_bytes;           // number of bytes read after last pts stamp
   int eof;                 // end of demuxed stream? (true if all buffer empty)
@@ -70,6 +72,7 @@
   int bytes;              // total bytes of packets in buffer
   demux_packet_t *first;  // read to current buffer from here
   demux_packet_t *last;   // append new packets from input stream to here
+  demux_packet_t *current;// needed for refcounting of the buffer
   int id;                 // stream ID  (for multiple audio/video streams)
   struct demuxer_st *demuxer; // parent demuxer structure (stream handler)
 // ---- asf -----
@@ -123,11 +126,33 @@
   dp->pts=0;
   dp->pos=0;
   dp->flags=0;
+  dp->refcount=1;
+  dp->master=NULL;
+  return dp;
+}
+
+inline static demux_packet_t* clone_demux_packet(demux_packet_t* pack){
+  demux_packet_t* dp=malloc(sizeof(demux_packet_t));
+  while(pack->master) pack=pack->master; // find the master
+  memcpy(dp,pack,sizeof(demux_packet_t));
+  dp->next=NULL;
+  dp->refcount=0;
+  dp->master=pack;
+  pack->refcount++;
   return dp;
 }
 
 inline static void free_demux_packet(demux_packet_t* dp){
-  free(dp->buffer);
+  if (dp->master==NULL){  //dp is a master packet
+    dp->refcount--;
+    if (dp->refcount==0){
+      if (dp->buffer) free(dp->buffer);
+      free(dp);
+    }
+    return;
+  }
+  // dp is a clone:
+  free_demux_packet(dp->master);
   free(dp);
 }