All pastes #409182 Raw Edit

Unnamed

public text v1 · immutable
#409182 ·published 2007-03-25 14:42 UTC
rendered paste body
Index: apps/plugins/mpegplayer/mpegplayer.c
===================================================================
--- apps/plugins/mpegplayer/mpegplayer.c	(revision 12900)
+++ apps/plugins/mpegplayer/mpegplayer.c	(working copy)
@@ -172,8 +172,11 @@
    uint8_t* curr_packet;        /* Current stream packet beginning */
    uint8_t* curr_packet_end;    /* Current stream packet end */
 
-   uint8_t* next_packet;        /* Next stream packet beginning */    
- 
+   uint8_t* prev_packet;        /* Previous stream packet beginning */
+   uint8_t* next_packet;        /* Next stream packet beginning */
+
+   size_t guard_bytes;          /* Number of bytes in guardbuf used */
+   size_t buffer_remaining;     /* How much data is left in the buffer */ 
    int id;
 } Stream;
 
@@ -184,6 +187,10 @@
    on the ipod (reason unknown)
 */
 static uint8_t *disk_buf, *disk_buf_end;
+static uint8_t *disk_buf_tail IBSS_ATTR;
+static uint8_t *disk_buf_head IBSS_ATTR;
+static size_t disk_buf_len IBSS_ATTR;
+static size_t buffer_size IBSS_ATTR;
 
 /* Events */
 static struct event_queue msg_queue IBSS_ATTR;
@@ -211,8 +218,17 @@
 /* TODO: Can we reduce the PCM buffer size? */
 #define PCMBUFFER_SIZE (512*1024)
 #define AUDIOBUFFER_SIZE (32*1024)
+#ifdef SIMULATOR
+/* Make this large, so the main buffer is small - for testing buffering */
 #define LIBMPEG2BUFFER_SIZE (2*1024*1024)
+#else
+#define LIBMPEG2BUFFER_SIZE (2*1024*1024)
+#endif
 
+/* TODO: Is 32KB enough?  */
+#define MPEG_GUARDBUF_SIZE (32*1024)
+#define MPEG_LOW_WATERMARK (1024*1024)
+
 static void button_loop(void)
 {
     bool result;
@@ -344,7 +360,7 @@
 uint8_t system_header_start_code [4] = { 0x00, 0x00, 0x01, 0xbb };
 
 /* This function demux the streams and give the next stream data pointer */
-static void get_next_data( Stream* str )
+static void get_next_data( Stream* str)
 {
     uint8_t *p;
     uint8_t *header;
@@ -358,6 +374,7 @@
         /* What does this do? */
         while( (p = disk_buf) == NULL )
         {
+DEBUGF("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n");
             rb->lcd_putsxy(0,LCD_HEIGHT-10,"FREEZE!");
             rb->lcd_update();
             rb->sleep(100);
@@ -365,11 +382,17 @@
     } else {
         p = str->curr_packet_end;
     }
-    
+
     for( ;; )
     {
         int length, bytes;
         
+            if( p >= disk_buf_end )
+            {
+                p = disk_buf + (p - disk_buf_end);
+DEBUGF("**** Wrapping pointer for %02x\n",str->id);
+            }
+
         /* Pack header, skip it */
         if( rb->memcmp (p, pack_start_code, sizeof (pack_start_code)) == 0 )
         {
@@ -397,6 +420,11 @@
             /*rb->splash( 30, "System header" );*/
         }
         
+            if( p > disk_buf_end )
+            {
+                DEBUGF("REBUFFERING NEEDED... 3\n");
+            }
+
         /* Packet header, parse it */
         if( rb->memcmp (p, packet_start_code_prefix, sizeof (packet_start_code_prefix)) != 0 )
         {
@@ -428,6 +456,11 @@
             continue;
         }
         
+            if( p > disk_buf_end )
+            {
+                DEBUGF("REBUFFERING NEEDED... 4\n");
+            }
+
         /* Ok, it's our packet */
         str->curr_packet_end = p + length+6;    
         header = p;
@@ -461,6 +494,7 @@
                 if (length > 23) 
                 {
                     rb->splash( 30, "Too much stuffing" );
+DEBUGF("Too much stuffing" );
                     break;
                 }
             }
@@ -488,20 +522,37 @@
                     mpeg2_tag_picture (mpeg2dec, pts, dts);
             }
         }
+
         p += length;
         bytes = 6 + (header[4] << 8) + header[5] - length;
         if (bytes > 0) {
-            /*str->curr_packet_end = p+bytes;*/
+            str->curr_packet_end = p+bytes;
+            //DEBUGF("prev = %d, curr = %d\n",str->prev_packet,str->curr_packet);
+
+            if (str->curr_packet != NULL) {
+                if (str->curr_packet < str->prev_packet) {
+                    str->buffer_remaining -= (disk_buf_end - str->prev_packet) + (str->curr_packet - disk_buf);
+                    str->buffer_remaining -= str->guard_bytes;
+                    str->guard_bytes = 0;
+                } else {
+                    str->buffer_remaining -= (str->curr_packet - str->prev_packet);
+                }
+
+                str->prev_packet = str->curr_packet;
+            }
+
+            DEBUGF("audio = %d, video = %d\n",audio_str.buffer_remaining,video_str.buffer_remaining);
+
             str->curr_packet = p;
-            return;
+
+            if( str->curr_packet_end > disk_buf_end )
+            {
+                str->guard_bytes = str->curr_packet_end-disk_buf_end;
+                rb->memcpy(disk_buf_end,disk_buf,str->guard_bytes);
+                DEBUGF("memcpy to guard buffer - curr_packet=%d, curr_packet_end=%d, disk_buf_end=%d\n",str->curr_packet,str->curr_packet_end,disk_buf_end);
+            }
+            return ;
         }
-        
-        if( str->curr_packet_end > disk_buf_end )
-        {
-            /* We should ask for buffering here */
-            str->curr_packet_end = str->curr_packet = NULL;
-            return;
-        }
                 
         break;
     }    
@@ -575,8 +626,9 @@
            goto done;
         }
 
-        if (n < 1000) {  /* TODO: What is the maximum size of an MPEG audio frame? */
+        if (n < 1500) {  /* TODO: What is the maximum size of an MPEG audio frame? */
             get_next_data( &audio_str );
+DEBUGF("audio_str.curr_packet=%d, disk_buf=%d, disk_buf_end=%d\n",audio_str.curr_packet,disk_buf,disk_buf_end);
             if (audio_str.curr_packet == NULL) {
                 /* Wait for audio to finish */
                 while (pcmbuf_len > 0) { rb->sleep(HZ/10); }
@@ -585,6 +637,7 @@
             len = audio_str.curr_packet_end - audio_str.curr_packet;
             if (n + len > mpa_buffer_size) { 
                 rb->splash( 30, "Audio buffer overflow" );
+DEBUGF("Audio buffer overflow" );
                 audiostatus=STREAM_DONE;
                 /* Wait to be killed */
                 for (;;) { rb->sleep(HZ); }
@@ -599,6 +652,7 @@
         }
 
         if (mad_frame_decode(&frame, &stream)) {
+DEBUGF("Audio stream error - %d\n",stream.error);
             if (stream.error == MAD_FLAG_INCOMPLETE
                 || stream.error == MAD_ERROR_BUFLEN) {
                 /* This makes the codec support partially corrupted files */
@@ -620,6 +674,7 @@
                 continue;
             } else {
                 /* Some other unrecoverable error */
+DEBUGF("Unrecoverable error\n");
                 break;
             }
             break;
@@ -632,11 +687,13 @@
         /* TODO: Don't memmove so much... */
         if (stream.next_frame) {
             len = stream.next_frame - mpa_buffer;
+DEBUGF("len=%d\n",len);
             rb->memmove(mpa_buffer,stream.next_frame,n-len);
             n -= len;
         } else {
             /* What to do here? */
             goto done;
+DEBUGF("/* What to do here? */\n");
         }
 #if 0
         /* The mpa.c version: */
@@ -714,6 +771,7 @@
 done:
     rb->pcm_play_stop();
     audiostatus=STREAM_DONE;
+DEBUGF("Audio thread ended." );
 
     for (;;) {  
         button_loop();
@@ -723,7 +781,7 @@
 
 /* End of libmad stuff */
 
-static uint64_t eta IBSS_ATTR;
+static int64_t eta IBSS_ATTR;
 
 /* TODO: Running in the main thread, libmad needs 8.25KB of stack.
    The codec thread uses a 9KB stack.  So we can probable reduce this a
@@ -745,9 +803,9 @@
     int skipcount = 0;
     int frame = 0;
     int lasttick;
-    unsigned int eta2;
-    unsigned int s;
-    int fps;
+    int64_t eta2;
+    int64_t s;
+    int64_t fps;
 
     rb->sleep(HZ/5);
     mpeg2dec = mpeg2_init ();
@@ -820,6 +878,7 @@
 
                 /*  Convert eta (in 27MHz ticks) into audio samples */
                 eta2 =(eta * 44100) / 27000000;
+
                 s = samplesplayed - (rb->pcm_get_bytes_waiting() >> 2);
                 if (settings.limitfps) {
                     if (eta2 > s) {
@@ -841,9 +900,11 @@
                 /* Calculate fps */
                 frame++;
                 if (settings.showfps && (*rb->current_tick-lasttick>=HZ)) {
-                    fps=(frame*441000)/s;
+                    fps=frame;
+                    fps*=441000;
+                    fps/=s;
                     rb->snprintf(str,sizeof(str),"%d.%d %d %d %d",
-                                 (fps/10),fps%10,skipped,s,eta2);
+                                 (int)(fps/10),(int)(fps%10),skipped,(int)s,(int)eta2);
                     rb->lcd_putsxy(0,0,str);
                     rb->lcd_update_rect(0,0,LCD_WIDTH,8);
         
@@ -870,7 +931,10 @@
     int audiosize;
     int in_file;
     uint8_t* buffer;
-    size_t buffer_size;
+    size_t audio_remaining, video_remaining;
+    size_t bytes_to_read;
+    size_t file_remaining;
+    size_t n;
 
     /* We define this here so it is on the main stack (in IRAM) */
     mad_fixed_t mad_frame_overlap[2][32][18];       /* 4608 bytes */
@@ -898,7 +962,13 @@
     /* Grab most of the buffer for the compressed video - leave some for 
        PCM audio data and some for libmpeg2 malloc use. */
     buffer_size = audiosize - (PCMBUFFER_SIZE+AUDIOBUFFER_SIZE+LIBMPEG2BUFFER_SIZE);
+
     DEBUGF("audiosize=%d, buffer_size=%ld\n",audiosize,buffer_size);
+    buffer_size &= ~(0x7ff);  /* Round buffer down to nearest 2KB */
+#ifdef SIMULATOR
+    buffer_size = 28096512;
+#endif
+    DEBUGF("audiosize=%d, buffer_size=%ld\n",audiosize,buffer_size);
     buffer = mpeg2_malloc(buffer_size,-1);
 
     if (buffer == NULL)
@@ -961,11 +1031,22 @@
 
     eta = 0;
 
-    rb->splash(0, "Buffering...");
+    rb->splash(0, "Buffering %d",(int)buffer_size);
 
-    disk_buf_end = buffer + rb->read (in_file, buffer, buffer_size);
+    file_remaining = rb->filesize(in_file);
+    disk_buf_end = buffer + buffer_size-MPEG_GUARDBUF_SIZE;
+    disk_buf_len = rb->read (in_file, buffer, buffer_size-MPEG_GUARDBUF_SIZE);
     disk_buf = buffer;
+    disk_buf_head = buffer;
+    disk_buf_tail = buffer;
 
+    video_str.guard_bytes = audio_str.guard_bytes = 0;
+    video_str.prev_packet = disk_buf;
+    audio_str.prev_packet = disk_buf;
+    video_str.buffer_remaining = disk_buf_len;
+    audio_str.buffer_remaining = disk_buf_len;
+
+    //DEBUGF("START: video = %d, audio = %d\n",audio_str.buffer_remaining,video_str.buffer_remaining);
     rb->lcd_setfont(FONT_SYSFIXED);
 
     audiostatus = STREAM_BUFFERING;
@@ -991,6 +1072,31 @@
 
     /* Wait until both threads have finished their work */
     while ((audiostatus != STREAM_DONE) || (videostatus != STREAM_DONE)) { 
+        audio_remaining = audio_str.buffer_remaining;
+        video_remaining = video_str.buffer_remaining;
+        if (MIN(audio_remaining,video_remaining) < MPEG_LOW_WATERMARK) {
+
+            // TODO: Read in chunks, add mutex when updating the A/V buffer_remaining variables.
+            bytes_to_read = buffer_size - MPEG_GUARDBUF_SIZE - MAX(audio_remaining,video_remaining);
+
+            bytes_to_read = MIN(bytes_to_read,(size_t)(disk_buf_end-disk_buf_tail));
+
+            while (( bytes_to_read > 0) && (file_remaining > 0)) {
+                n = rb->read(in_file, disk_buf_tail, MIN(128*1024,bytes_to_read));
+                DEBUGF("Read %d bytes, bytes_to_read = %d\n",n,bytes_to_read);
+                DEBUGF("buffer = %d, disk_buf_tail = %d\n",buffer, disk_buf_tail);
+                bytes_to_read -= n;
+                file_remaining -= n;
+                audio_str.buffer_remaining += n;
+                video_str.buffer_remaining += n;
+                disk_buf_tail += n;
+                rb->yield();
+            }
+
+            if (disk_buf_tail == disk_buf_end)
+                disk_buf_tail = buffer;
+
+        }
         rb->sleep(HZ/10);
     }