diff --exclude=.svn -Naur rockbox_svn_2007-07-25/apps/plugin.c rockbox/apps/plugin.c --- rockbox_svn_2007-07-25/apps/plugin.c 2007-07-25 13:52:52.000000000 -0400 +++ rockbox/apps/plugin.c 2007-07-25 13:54:48.000000000 -0400 @@ -191,6 +191,7 @@ gui_synclist_set_title, /* button */ + button_available, button_get, button_get_w_tmo, button_status, diff --exclude=.svn -Naur rockbox_svn_2007-07-25/apps/plugin.h rockbox/apps/plugin.h --- rockbox_svn_2007-07-25/apps/plugin.h 2007-07-25 13:52:52.000000000 -0400 +++ rockbox/apps/plugin.h 2007-07-25 13:54:48.000000000 -0400 @@ -280,6 +280,7 @@ void (*gui_synclist_set_title)(struct gui_synclist *lists, char* title, int icon); /* button */ + int (*button_available)(void); long (*button_get)(bool block); long (*button_get_w_tmo)(int ticks); int (*button_status)(void); diff --exclude=.svn -Naur rockbox_svn_2007-07-25/apps/plugins/mpegplayer/alloc.c rockbox/apps/plugins/mpegplayer/alloc.c --- rockbox_svn_2007-07-25/apps/plugins/mpegplayer/alloc.c 2007-07-25 13:52:36.000000000 -0400 +++ rockbox/apps/plugins/mpegplayer/alloc.c 2007-07-26 12:23:13.000000000 -0400 @@ -47,7 +47,6 @@ (void)reason; - DEBUGF("mpeg2_malloc(%d,%d)\n",size,reason); if (mem_ptr + (long)size > bufsize) { DEBUGF("OUT OF MEMORY\n"); return NULL; @@ -56,11 +55,14 @@ x=&mallocbuf[mem_ptr]; mem_ptr+=(size+3)&~3; /* Keep memory 32-bit aligned */ + rb->memset(x,0,size); + + DEBUGF("mpeg2_malloc(%u,%d,%d)\n",x,size,reason); return(x); } void mpeg2_free(void* ptr) { - (void)ptr; + mem_ptr = (void *)ptr - (void *)mallocbuf; } /* gcc may want to use memcpy before rb is initialised, so here's a trivial diff --exclude=.svn -Naur rockbox_svn_2007-07-25/apps/plugins/mpegplayer/header.c rockbox/apps/plugins/mpegplayer/header.c --- rockbox_svn_2007-07-25/apps/plugins/mpegplayer/header.c 2007-07-25 13:52:36.000000000 -0400 +++ rockbox/apps/plugins/mpegplayer/header.c 2007-07-25 13:54:48.000000000 -0400 @@ -58,7 +58,7 @@ 83 }; -uint8_t mpeg2_scan_norm[64] IDATA_ATTR = { +uint8_t default_mpeg2_scan_norm[64] IDATA_ATTR = { /* Zig-Zag scan pattern */ 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32, 25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14, 21, 28, @@ -66,7 +66,7 @@ 58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63 }; -uint8_t mpeg2_scan_alt[64] IDATA_ATTR = { +uint8_t default_mpeg2_scan_alt[64] IDATA_ATTR = { /* Alternate scan pattern */ 0, 8, 16, 24, 1, 9, 2, 10, 17, 25, 32, 40, 48, 56, 57, 49, 41, 33, 26, 18, 3, 11, 4, 12, 19, 27, 34, 42, 50, 58, 35, 43, @@ -74,6 +74,9 @@ 53, 61, 22, 30, 7, 15, 23, 31, 38, 46, 54, 62, 39, 47, 55, 63 }; +uint8_t mpeg2_scan_norm[64] IDATA_ATTR; +uint8_t mpeg2_scan_alt[64] IDATA_ATTR; + void mpeg2_header_state_init (mpeg2dec_t * mpeg2dec) { if (mpeg2dec->sequence.width != (unsigned)-1) { diff --exclude=.svn -Naur rockbox_svn_2007-07-25/apps/plugins/mpegplayer/idct.c rockbox/apps/plugins/mpegplayer/idct.c --- rockbox_svn_2007-07-25/apps/plugins/mpegplayer/idct.c 2007-07-25 13:52:36.000000000 -0400 +++ rockbox/apps/plugins/mpegplayer/idct.c 2007-07-25 13:54:48.000000000 -0400 @@ -260,6 +260,8 @@ void mpeg2_idct_init (void) { + extern uint8_t default_mpeg2_scan_norm[64]; + extern uint8_t default_mpeg2_scan_alt[64]; extern uint8_t mpeg2_scan_norm[64]; extern uint8_t mpeg2_scan_alt[64]; int i, j; @@ -274,10 +276,10 @@ for (i = 0; i < 64; i++) { - j = mpeg2_scan_norm[i]; + j = default_mpeg2_scan_norm[i]; mpeg2_scan_norm[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); - j = mpeg2_scan_alt[i]; + j = default_mpeg2_scan_alt[i]; mpeg2_scan_alt[i] = ((j & 0x36) >> 1) | ((j & 0x09) << 2); } } diff --exclude=.svn -Naur rockbox_svn_2007-07-25/apps/plugins/mpegplayer/mpegplayer.c rockbox/apps/plugins/mpegplayer/mpegplayer.c --- rockbox_svn_2007-07-25/apps/plugins/mpegplayer/mpegplayer.c 2007-07-25 13:52:36.000000000 -0400 +++ rockbox/apps/plugins/mpegplayer/mpegplayer.c 2007-07-26 13:21:50.000000000 -0400 @@ -109,6 +109,7 @@ #include "mpeg_settings.h" #include "video_out.h" #include "../../codecs/libmad/mad.h" +#include "splash.h" PLUGIN_HEADER PLUGIN_IRAM_DECLARE @@ -183,9 +184,7 @@ uint8_t* curr_packet_end; /* Current stream packet end */ 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 prev_packet_length; /* Lenth of previous packet */ size_t buffer_remaining; /* How much data is left in the buffer */ uint32_t curr_pts; /* Current presentation timestamp */ uint32_t curr_time; /* Current time in samples */ @@ -331,10 +330,20 @@ /* NOTE: Putting the following variables in IRAM cause audio corruption on the ipod (reason unknown) */ -static uint8_t *disk_buf IBSS_ATTR; -static uint8_t *disk_buf_end IBSS_ATTR; -static uint8_t *disk_buf_tail IBSS_ATTR; -static size_t buffer_size IBSS_ATTR; +static uint8_t *disk_buf_start IBSS_ATTR; /* Start pointer */ +static uint8_t *disk_buf_end IBSS_ATTR; /* End of buffer pointer less + MPEG_GUARDBUF_SIZE. The + guard space is used to wrap + data at the buffer start to + pass continuous data + packets */ +static uint8_t *disk_buf_tail IBSS_ATTR; /* Location of last data + 1 + filled into the buffer */ +static size_t disk_buf_size IBSS_ATTR; /* The total buffer length + including the guard + space */ +static size_t file_remaining IBSS_ATTR; + #if NUM_CORES > 1 /* Some stream variables are shared between cores */ struct mutex stream_lock IBSS_ATTR; @@ -354,11 +363,29 @@ { } #endif -/* Events */ -static struct event_queue msg_queue IBSS_ATTR; +static int audio_sync_start IBSS_ATTR; /* If 0, the audio thread + yields waiting on the video + thread to synchronize with + the stream */ +static uint32_t audio_sync_time IBSS_ATTR; /* The time that the video + thread has reached after + synchronizing. The + audio thread now needs + to advance to this + time */ +static int video_sync_start IBSS_ATTR; /* While 0, the video thread + yields until the audio + thread has reached the + audio_sync_time */ +static int video_thumb_print IBSS_ATTR; /* If 1, the video thread is + only decoding one frame for + use in the menu. If 0, + normal operation */ +static int play_time IBSS_ATTR; /* The movie time as represented by + the maximum audio PTS tag in the + stream converted to minutes */ +char *filename; /* hack for resume time storage */ -#define MSG_BUFFER_NEARLY_EMPTY 1 -#define MSG_EXIT_REQUESTED 2 /* Various buffers */ /* TODO: Can we reduce the PCM buffer size? */ @@ -369,7 +396,7 @@ #define LIBMPEG2BUFFER_SIZE (2*1024*1024) /* 65536+6 is required since each PES has a 6 byte header with a 16 bit packet length field */ -#define MPEG_GUARDBUF_SIZE (64*1024+1024) /* Keep a bit extra - excessive for now */ +#define MPEG_GUARDBUF_SIZE (65*1024) /* Keep a bit extra - excessive for now */ #define MPEG_LOW_WATERMARK (1024*1024) static void pcm_playback_play_pause(bool play); @@ -490,8 +517,47 @@ ((p)[b3] << 6) | \ ((p)[b4] >> 2 ))) -/* This function demuxes the streams and gives the next stream data pointer */ -static void get_next_data( Stream* str ) +/* This function synchronizes the mpeg stream. The function returns + true on error */ +bool sync_data_stream(uint8_t **p) +{ + for (;;) + { + while ( !CMP_4_CONST(*p, PACK_START_CODE) && (*p) < disk_buf_tail ) + (*p)++; + if ( (*p) >= disk_buf_tail ) + break; + uint8_t *p_save = (*p); + if ( ((*p)[4] & 0xc0) == 0x40 ) /* mpeg-2 */ + (*p) += 14 + ((*p)[13] & 7); + else if ( ((*p)[4] & 0xf0) == 0x20 ) /* mpeg-1 */ + (*p) += 12; + else + (*p) += 5; + if ( (*p) >= disk_buf_tail ) + break; + if ( CMP_3_CONST(*p, PACKET_START_CODE_PREFIX) ) + { + (*p) = p_save; + break; + } + else + (*p) = p_save+1; + } + + if ( (*p) >= disk_buf_tail ) + return true; + else + return false; +} + +/* This function demuxes the streams and gives the next stream data + pointer. Type 0 is normal operation. Type 1 and 2 have been added + for rapid seeks into the data stream. Type 1 and 2 ignore the + video_sync_start state (a signal to yield for refilling the + buffer). Type 1 will append maore data to the buffer tail (minumal + bufer size reads that are increased only as needed). */ +static int get_next_data( Stream* str, uint8_t type ) { uint8_t *p; uint8_t *header; @@ -500,30 +566,34 @@ static int mpeg1_skip_table[16] = { 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; - if (str->curr_packet_end == NULL) - { - /* What does this do? */ - while ((p = disk_buf) == NULL) - { - rb->lcd_putsxy(0,LCD_HEIGHT-10,"FREEZE!"); - rb->lcd_update(); - rb->sleep(HZ); - } - } - else - { - p = str->curr_packet_end; - } + if ( (p=str->curr_packet_end) == NULL) + p = disk_buf_start; while (1) { int length, bytes; - - if (p >= disk_buf_end) + + /* Yield for buffer filling */ + if ( (type == 0) && (str->buffer_remaining < 120*1024) && (file_remaining > 0) ) + while ( (str->buffer_remaining < 512*1024) && (file_remaining > 0) ) + rb->yield(); + + /* The packet start position (plus an arbitrary header length) + has exceeded the amount of data in the buffer */ + if ( type == 1 && (p+50) >= disk_buf_tail ) { - p = disk_buf + (p - disk_buf_end); + DEBUGF("disk buffer overflow\n"); + return 1; } + /* wrap the disk buffer */ + if (p >= disk_buf_end) + p = disk_buf_start + (p - disk_buf_end); + + /* wrap packet header if needed */ + if ( (p+50) >= disk_buf_end ) + rb->memcpy(disk_buf_end, disk_buf_start, 50); + /* Pack header, skip it */ if (CMP_4_CONST(p, PACK_START_CODE)) { @@ -540,7 +610,6 @@ rb->splash( 30, "Weird Pack header!" ); p += 5; } - /*rb->splash( 30, "Pack header" );*/ } /* System header, parse and skip it - four bytes */ @@ -554,29 +623,30 @@ p += header_length; - if (p >= disk_buf_end) - { - p = disk_buf + (p - disk_buf_end); - } - /*rb->splash( 30, "System header" );*/ + if ( p >= disk_buf_end ) + p = disk_buf_start + (p - disk_buf_end); } - + /* Packet header, parse it */ if (!CMP_3_CONST(p, PACKET_START_CODE_PREFIX)) { /* Problem */ - //rb->splash( HZ*3, "missing packet start code prefix : %X%X at %X", *p, *(p+2), p-disk_buf ); + rb->splash( HZ*3, "missing packet start code prefix : %X%X at %lX", *p, *(p+2), p-disk_buf_start ); + + DEBUGF("end diff: %X,%X,%X,%X,%X,%X\n",(int)str->curr_packet_end,(int)audio_str.curr_packet_end,(int)video_str.curr_packet_end,(int)disk_buf_start,(int)disk_buf_end,(int)disk_buf_tail); + str->curr_packet_end = str->curr_packet = NULL; + + audio_sync_start=1; + video_sync_start=1; + break; - //++p; - //break; } /* We retrieve basic infos */ stream = p[3]; length = (p[4] << 8) | p[5]; - /*rb->splash( 100, "Stream : %X", stream );*/ if (stream != str->id) { /* End of stream ? */ @@ -637,11 +707,13 @@ break; } } - - if ((header[length - 1] & 0xc0) == 0x40) - { + + if ( (header[length - 1] & 0xc0) == 0x40 ) length += 2; - } + + + + len_skip = length; length += mpeg1_skip_table[header[length - 1] >> 4]; @@ -676,23 +748,17 @@ if (bytes > 0) { str->curr_packet_end = p + bytes; - //DEBUGF("prev = %d, curr = %d\n",str->prev_packet,str->curr_packet); if (str->curr_packet != NULL) { lock_stream(); + str->buffer_remaining -= str->prev_packet_length; 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; - } + str->prev_packet_length = (disk_buf_end - str->prev_packet) + + (str->curr_packet - disk_buf_start); else - { - str->buffer_remaining -= (str->curr_packet - str->prev_packet); - } + str->prev_packet_length = (str->curr_packet - str->prev_packet); unlock_stream(); @@ -702,14 +768,12 @@ str->curr_packet = p; 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); - } + rb->memcpy(disk_buf_end, disk_buf_start, str->curr_packet_end - disk_buf_end ); } break; } /* end while */ + return 0; } /* Our clock rate in ticks/second - this won't be a constant for long */ @@ -967,6 +1031,8 @@ int vol, minvol, maxvol; int button; + if (video_sync_start==1) { + if (str_have_msg(&audio_str)) { struct event ev; @@ -1048,6 +1114,7 @@ break; case MPEG_STOP: + store_resume_info(filename,(int)(get_stream_time()/44100/60)); str_send_msg(&video_str, STREAM_QUIT, 0); audio_str.status = STREAM_STOPPED; break; @@ -1084,7 +1151,7 @@ audio_str.status = STREAM_STOPPED; } } - + } quit: return audio_str.status; } @@ -1110,7 +1177,18 @@ pcm_playback_play(0); /* Get first packet */ - get_next_data(&audio_str); + get_next_data(&audio_str, 0 ); + + /* skip audio packets here */ + while (audio_sync_start==0) { + audio_str.status = STREAM_PLAYING; + rb->yield(); + } + + while (TS_TO_TICKS(audio_str.curr_pts) < audio_sync_time - 10000) { + get_next_data(&audio_str, 0 ); + rb->priority_yield(); + } if (audio_str.curr_packet == NULL) goto done; @@ -1189,7 +1267,7 @@ mpabuf = mpa_buffer; /* Get data from next audio packet */ - get_next_data(&audio_str); + get_next_data(&audio_str, 0 ); } while (audio_str.curr_packet != NULL && mpabuf_used < MPA_MAX_FRAME_SIZE + MAD_BUFFER_GUARD); @@ -1222,8 +1300,6 @@ if (mad_stat != 0) { - DEBUGF("Audio stream error - %d\n", stream.error); - if (stream.error == MAD_FLAG_INCOMPLETE || stream.error == MAD_ERROR_BUFLEN) { @@ -1283,6 +1359,12 @@ rb->priority_yield(); } + if (video_sync_start == 0 && pts->pts+(uint32_t)synth.pcm.lengthyield(); + } + /* TODO: This part will be replaced with dsp calls soon */ if (MAD_NCHANNELS(&frame.header) == 2) { @@ -1329,6 +1411,7 @@ audio_str.status = STREAM_PLAYING; pcmbuf_threshold = PCMBUF_PLAY_ALL; pcm_playback_seek_time(pcmbuf_tail->time); + video_sync_start = 1; } /* Make this data available to DMA */ @@ -1416,29 +1499,32 @@ /* Clear the display - this is mainly just to indicate that the video thread has started successfully. */ - rb->lcd_clear_display(); - rb->lcd_update(); + if (!video_thumb_print) + { + rb->lcd_clear_display(); + rb->lcd_update(); + } /* Request the first packet data */ - get_next_data( &video_str ); + get_next_data( &video_str, 0 ); if (video_str.curr_packet == NULL) - goto done; + goto video_thread_quit; mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end); total_offset += video_str.curr_packet_end - video_str.curr_packet; info = mpeg2_info (mpeg2dec); - /* Wait if the audio thread is buffering - i.e. before - the first frames are decoded */ - while (audio_str.status == STREAM_BUFFERING) - rb->priority_yield(); - while (1) { /* quickly check mailbox first */ - if (str_have_msg(&video_str)) + if (video_thumb_print) + { + if (video_str.status == STREAM_STOPPED) + break; + } + else if (str_have_msg(&video_str)) { while (1) { @@ -1473,7 +1559,8 @@ { case STATE_BUFFER: /* Request next packet data */ - get_next_data( &video_str ); + get_next_data( &video_str, 0 ); + mpeg2_buffer (mpeg2dec, video_str.curr_packet, video_str.curr_packet_end); total_offset += video_str.curr_packet_end - video_str.curr_packet; info = mpeg2_info (mpeg2dec); @@ -1481,7 +1568,7 @@ if (video_str.curr_packet == NULL) { /* No more data. */ - goto done; + goto video_thread_quit; } continue; @@ -1562,6 +1649,13 @@ period = TIME_TO_TICKS(info->sequence->frame_period); eta_video = curr_time; + + audio_sync_time = eta_video; + audio_sync_start = 1; + + while (video_sync_start == 0) + rb->yield(); + eta_audio = get_stream_time(); /* How early/late are we? > 0 = late, < 0 early */ @@ -1687,32 +1781,39 @@ picture_wait: /* Wait until audio catches up */ - while (eta_video > eta_audio) - { - rb->priority_yield(); - - /* Make sure not to get stuck waiting here forever */ - if (str_have_msg(&video_str)) + if (video_thumb_print) + video_str.status = STREAM_STOPPED; + else + while (eta_video > eta_audio) { - str_look_msg(&video_str, &ev); - - /* If not to play, process up top */ - if (ev.id != STREAM_PLAY) - goto rendering_finished; + rb->priority_yield(); + + /* Make sure not to get stuck waiting here forever */ + if (str_have_msg(&video_str)) + { + str_look_msg(&video_str, &ev); + + /* If not to play, process up top */ + if (ev.id != STREAM_PLAY) + goto rendering_finished; + + /* Told to play but already playing */ + str_get_msg(&video_str, &ev); + str_reply_msg(&video_str, 1); + } - /* Told to play but already playing */ - str_get_msg(&video_str, &ev); - str_reply_msg(&video_str, 1); + eta_audio = get_stream_time(); } - - eta_audio = get_stream_time(); - } - + picture_draw: /* Record last frame time */ last_render = *rb->current_tick; - vo_draw_frame(info->display_fbuf->buf); + if (video_thumb_print) + vo_draw_frame_thumb(info->display_fbuf->buf); + else + vo_draw_frame(info->display_fbuf->buf); + num_drawn++; picture_skip: @@ -1747,43 +1848,264 @@ rb->yield(); } -done: +video_thread_quit: flush_icache(); - video_str.status = STREAM_DONE; + mpeg2_close (mpeg2dec); - while (1) - { - str_get_msg(&video_str, &ev); + /* Commit suicide */ + video_str.status = STREAM_TERMINATED; + rb->remove_thread(NULL); +} - if (ev.id == STREAM_QUIT) - break; +void initialize_stream( Stream *str, uint8_t *buffer_start, size_t disk_buf_len, int id ) +{ + str->curr_packet_end = str->curr_packet = NULL; + str->prev_packet_length = 0; + str->prev_packet = str->curr_packet_end = buffer_start; + str->buffer_remaining = disk_buf_len; + str->id = id; +} + +void display_thumb(int in_file) +{ + size_t disk_buf_len; - str_reply_msg(&video_str, 0); + video_thumb_print = 1; + audio_sync_start = 1; + video_sync_start = 1; + + disk_buf_len = rb->read (in_file, disk_buf_start, disk_buf_size - MPEG_GUARDBUF_SIZE); + disk_buf_tail = disk_buf_start + disk_buf_len; + initialize_stream(&video_str,disk_buf_start,disk_buf_len,0xe0); + + video_str.status = STREAM_PLAYING; + + if ((video_str.thread = rb->create_thread(video_thread, + (uint8_t*)video_stack,VIDEO_STACKSIZE,"mpgvideo" + IF_PRIO(,PRIORITY_PLAYBACK) + IF_COP(, COP, true))) == NULL) + { + rb->splash(HZ, "Cannot create video thread!"); } + else + { + while (video_str.status != STREAM_TERMINATED) + rb->yield(); + } +} -video_thread_quit: - flush_icache(); +int find_length( int in_file ) +{ + uint8_t *p; + size_t read_length = 20*1024; + size_t disk_buf_len; + + /* temporary read buffer size cannot exceed buffer size */ + if ( read_length > disk_buf_size ) + read_length = disk_buf_size; + + /* read tail of file */ + rb->lseek( in_file, -1*read_length, SEEK_END ); + disk_buf_len = rb->read( in_file, disk_buf_start, read_length ); + disk_buf_tail = disk_buf_start + disk_buf_len; + + /* sync reader to this segment of the stream */ + p=disk_buf_start; + if (sync_data_stream(&p)) + { + DEBUGF("Could not sync stream\n"); + return PLUGIN_ERROR; + } + + /* find last PTS in audio stream; will movie always have audio? */ + audio_sync_start = 0; + audio_sync_time = 0; + video_sync_start = 0; + { + Stream tmp; + initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0); + + do + get_next_data(&tmp, 2); + while (tmp.curr_packet_end != NULL); + if (tmp.tagged == 1) + play_time = (int)(tmp.curr_pts/45000/60); + else + { + DEBUGF("Could not determine playtime\n"); + return PLUGIN_ERROR; + } + } + return 0; +} - /* Commit suicide */ - video_str.status = STREAM_TERMINATED; - rb->remove_thread(NULL); +ssize_t seek_PTS( int in_file, int start_time, int accept_button ) +{ + static ssize_t last_seek_pos = 0; + static int last_start_time = 0; + ssize_t seek_pos; + size_t disk_buf_len; + uint8_t *p; + size_t read_length = 20*1024; + + /* temporary read buffer size cannot exceed buffer size */ + if ( read_length > disk_buf_size ) + read_length = disk_buf_size; + + if ( start_time == last_start_time ) + { + seek_pos = last_seek_pos; + rb->lseek(in_file,seek_pos,SEEK_SET); + } + else if ( start_time != 0 ) + { + seek_pos = rb->filesize(in_file)*start_time/play_time; + int seek_pos_sec_inc = rb->filesize(in_file)/play_time/60; + + if (seek_pos<0) + seek_pos=0; + rb->lseek( in_file, seek_pos, SEEK_SET ); + disk_buf_len = rb->read( in_file, disk_buf_start, read_length ); + disk_buf_tail = disk_buf_start + disk_buf_len; + + /* sync reader to this segment of the stream */ + p=disk_buf_start; + if (sync_data_stream(&p)) + { + DEBUGF("Could not sync stream\n"); + return PLUGIN_ERROR; + } + + /* find PTS >= start_time */ + audio_sync_start = 0; + audio_sync_time = 0; + video_sync_start = 0; + { + Stream tmp; + initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0); + int cont_seek_loop = 1; + int coarse_seek = 1; + do + { + if ( accept_button ) + { + rb->yield(); + if (rb->button_available()) + return -101; + } + + while ( get_next_data(&tmp, 1) == 1 ) + { + if ( tmp.curr_packet_end == disk_buf_start ) + seek_pos += disk_buf_tail - disk_buf_start; + else + seek_pos += tmp.curr_packet_end - disk_buf_start; + rb->lseek( in_file, seek_pos, SEEK_SET ); + disk_buf_len = rb->read ( in_file, disk_buf_start, read_length ); + disk_buf_tail = disk_buf_start + disk_buf_len; + + /* sync reader to this segment of the stream */ + p=disk_buf_start; + initialize_stream(&tmp,p,disk_buf_len,0xc0); + } + + /* are we after start_time in the stream? */ + if ( coarse_seek && (int)(tmp.curr_pts/45000) >= start_time*60 ) + { + int time_to_backup = (int)(tmp.curr_pts/45000) - start_time*60; + if (time_to_backup == 0) + time_to_backup++; + seek_pos -= seek_pos_sec_inc * time_to_backup; + seek_pos_sec_inc -= seek_pos_sec_inc/20; /* for stability */ + if (seek_pos<0) + seek_pos=0; + rb->lseek( in_file, seek_pos, SEEK_SET ); + disk_buf_len = rb->read( in_file, disk_buf_start, read_length ); + disk_buf_tail = disk_buf_start + disk_buf_len; + + /* sync reader to this segment of the stream */ + p=disk_buf_start; + if (sync_data_stream(&p)) + { + DEBUGF("Could not sync stream\n"); + return PLUGIN_ERROR; + } + initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0); + continue; + } + + /* are we well before start_time in the stream? */ + if ( coarse_seek && start_time*60 - (int)(tmp.curr_pts/45000) > 2 ) + { + int time_to_advance = start_time*60 - (int)(tmp.curr_pts/45000) - 2; + if (time_to_advance <= 0) + time_to_advance = 1; + seek_pos += seek_pos_sec_inc * time_to_advance; + if (seek_pos<0) + seek_pos=0; + rb->lseek( in_file, seek_pos, SEEK_SET ); + disk_buf_len = rb->read ( in_file, disk_buf_start, read_length ); + disk_buf_tail = disk_buf_start + disk_buf_len; + + /* sync reader to this segment of the stream */ + p=disk_buf_start; + if (sync_data_stream(&p)) + { + DEBUGF("Could not sync stream\n"); + return PLUGIN_ERROR; + } + initialize_stream(&tmp,p,disk_buf_len-(disk_buf_start-p),0xc0); + continue; + } + + coarse_seek = 0; + + /* are we at start_time in the stream? */ + if ( (int)(tmp.curr_pts/45000) >= start_time*60 ) + cont_seek_loop = 0; + + } + while ( cont_seek_loop ); + + + DEBUGF("start diff: %u %u\n",(unsigned int)(tmp.curr_pts/45000),start_time*60); + seek_pos+=tmp.curr_packet_end-disk_buf_start; + + last_seek_pos = seek_pos; + last_start_time = start_time; + + rb->lseek(in_file,seek_pos,SEEK_SET); + } + } + else + { + seek_pos = 0; + rb->lseek(in_file,0,SEEK_SET); + last_seek_pos = seek_pos; + last_start_time = start_time; + } + return seek_pos; } enum plugin_status plugin_start(struct plugin_api* api, void* parameter) { int status = PLUGIN_ERROR; /* assume failure */ + int start_time=-1; void* audiobuf; ssize_t audiosize; int in_file; - uint8_t* buffer; - size_t file_remaining; size_t disk_buf_len; + ssize_t seek_pos; #ifndef HAVE_LCD_COLOR long graysize; int grayscales; #endif + audio_sync_start = 0; + audio_sync_time = 0; + video_sync_start = 0; + if (parameter == NULL) { api->splash(HZ*2, "No File"); @@ -1795,6 +2117,7 @@ rb = api; + /* sets audiosize and returns buffer pointer */ audiobuf = rb->plugin_get_audio_buffer(&audiosize); #if INPUT_SRC_CAPS != 0 @@ -1805,46 +2128,35 @@ rb->pcm_set_frequency(SAMPR_44); - /* Set disk pointers to NULL */ - disk_buf_end = disk_buf = NULL; - - /* Stream construction */ - /* We take the first stream of each (audio and video) */ - /* TODO : Search for these in the file first */ - audio_str.curr_packet_end = audio_str.curr_packet = audio_str.next_packet = NULL; - video_str = audio_str; - video_str.id = 0xe0; - audio_str.id = 0xc0; +#ifndef HAVE_LCD_COLOR + /* initialize the grayscale buffer: 32 bitplanes for 33 shades of gray. */ + grayscales = gray_init(rb, audiobuf, audiosize, false, LCD_WIDTH, LCD_HEIGHT, + 32, 2<<8, &graysize) + 1; + audiobuf += graysize; + audiosize -= graysize; + if (grayscales < 33 || audiosize <= 0) + { + rb->splash(HZ, "gray buf error"); + return PLUGIN_ERROR; + } +#endif /* Initialise our malloc buffer */ mpeg2_alloc_init(audiobuf,audiosize); + /* Set disk pointers to NULL */ + disk_buf_end = disk_buf_start = NULL; + /* 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+PCMBUFFER_GUARD_SIZE+ + disk_buf_size = audiosize - (PCMBUFFER_SIZE+PCMBUFFER_GUARD_SIZE+ MPABUF_SIZE+LIBMPEG2BUFFER_SIZE); - DEBUGF("audiosize=%ld, buffer_size=%ld\n",audiosize,buffer_size); - buffer = mpeg2_malloc(buffer_size,-1); - - if (buffer == NULL) - return PLUGIN_ERROR; + DEBUGF("audiosize=%ld, disk_buf_size=%ld\n",audiosize,disk_buf_size); + disk_buf_start = mpeg2_malloc(disk_buf_size,-1); -#ifndef HAVE_LCD_COLOR - /* initialize the grayscale buffer: 32 bitplanes for 33 shades of gray. */ - grayscales = gray_init(rb, buffer, buffer_size, false, LCD_WIDTH, LCD_HEIGHT, - 32, 2<<8, &graysize) + 1; - buffer += graysize; - buffer_size -= graysize; - if (grayscales < 33 || buffer_size <= 0) - { - rb->splash(HZ, "gray buf error"); + if (disk_buf_start == NULL) return PLUGIN_ERROR; - } -#endif - - buffer_size &= ~(0x7ff); /* Round buffer down to nearest 2KB */ - DEBUGF("audiosize=%ld, buffer_size=%ld\n",audiosize,buffer_size); if (!init_mpabuf()) return PLUGIN_ERROR; @@ -1858,9 +2170,10 @@ in_file = rb->open((char*)parameter,O_RDONLY); if (in_file < 0){ - //fprintf(stderr,"Could not open %s\n",argv[1]); + DEBUGF("Could not open %s\n",(char*)parameter); return PLUGIN_ERROR; } + filename = (char*)parameter; #ifdef HAVE_LCD_COLOR rb->lcd_set_backdrop(NULL); @@ -1889,33 +2202,50 @@ init_settings(); - /* Msg queue init - no need for queue_remove since it's not a registered - queue */ - rb->queue_init( &msg_queue, false ); - /* Initialise libmad */ rb->memset(mad_frame_overlap, 0, sizeof(mad_frame_overlap)); init_mad(mad_frame_overlap); file_remaining = rb->filesize(in_file); - disk_buf_end = buffer + buffer_size-MPEG_GUARDBUF_SIZE; + disk_buf_end = disk_buf_start + disk_buf_size-MPEG_GUARDBUF_SIZE; + + /* initalize play_time with the length (in minutes) of the movie */ + { + int status = find_length( in_file ); + if (status) + return status; + } + + /* start menu */ + start_time = mpeg_start_menu((char*)parameter, play_time, in_file); + if ( start_time < 0 ) + start_time = 0; + if ( start_time > play_time ) + start_time = play_time; + + rb->splash(0, "loading ..."); + + /* seek start time */ + seek_pos = seek_PTS( in_file, start_time, 0 ); + + rb->lseek(in_file,seek_pos,SEEK_SET); + video_thumb_print = 0; + audio_sync_start = 0; + audio_sync_time = 0; + video_sync_start = 0; /* Read some stream data */ - disk_buf_len = rb->read (in_file, buffer, MPEG_LOW_WATERMARK); + disk_buf_len = rb->read (in_file, disk_buf_start, disk_buf_size - MPEG_GUARDBUF_SIZE); - DEBUGF("Initial Buffering - %d bytes\n",(int)disk_buf_len); - disk_buf = buffer; - disk_buf_tail = buffer+disk_buf_len; - file_remaining -= disk_buf_len; - - 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; + disk_buf_tail = disk_buf_start + disk_buf_len; + file_remaining -= disk_buf_len + seek_pos; + + initialize_stream( &video_str, disk_buf_start, disk_buf_len, 0xe0 ); + initialize_stream( &audio_str, disk_buf_start, disk_buf_len, 0xc0 ); rb->spinlock_init(&audio_str.msg_lock); rb->spinlock_init(&video_str.msg_lock); + audio_str.status = STREAM_BUFFERING; video_str.status = STREAM_PLAYING; @@ -1949,16 +2279,28 @@ size_t audio_remaining = audio_str.buffer_remaining; size_t video_remaining = video_str.buffer_remaining; - if (MIN(audio_remaining,video_remaining) < MPEG_LOW_WATERMARK) { + if (MIN(audio_remaining,video_remaining) < MPEG_LOW_WATERMARK) + { - size_t bytes_to_read = buffer_size - MPEG_GUARDBUF_SIZE - + size_t bytes_to_read = disk_buf_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) && - ((audio_str.status >= 0) || (video_str.status >= 0))) { - size_t n = rb->read(in_file, disk_buf_tail, MIN(32*1024,bytes_to_read)); + ((audio_str.status != STREAM_DONE) || (video_str.status != STREAM_DONE))) + { + + size_t n; + if ( video_sync_start != 0 ) + n = rb->read(in_file, disk_buf_tail, MIN(32*1024,bytes_to_read)); + else + { + n = rb->read(in_file, disk_buf_tail,bytes_to_read); + if (n==0) + rb->splash(30,"buffer fill error"); + } + bytes_to_read -= n; file_remaining -= n; @@ -1974,7 +2316,7 @@ } if (disk_buf_tail == disk_buf_end) - disk_buf_tail = buffer; + disk_buf_tail = disk_buf_start; } rb->sleep(HZ/10); @@ -2000,8 +2342,6 @@ rb->lcd_clear_display(); rb->lcd_update(); - mpeg2_close (mpeg2dec); - rb->close (in_file); #ifdef HAVE_ADJUSTABLE_CPU_FREQ diff --exclude=.svn -Naur rockbox_svn_2007-07-25/apps/plugins/mpegplayer/mpeg_settings.c rockbox/apps/plugins/mpegplayer/mpeg_settings.c --- rockbox_svn_2007-07-25/apps/plugins/mpegplayer/mpeg_settings.c 2007-07-25 13:52:36.000000000 -0400 +++ rockbox/apps/plugins/mpegplayer/mpeg_settings.c 2007-07-26 13:24:15.000000000 -0400 @@ -9,10 +9,99 @@ struct mpeg_settings settings; static struct mpeg_settings old_settings; +ssize_t seek_PTS(int in_file, int startTime, int accept_button); +void display_thumb(int in_file); + #define SETTINGS_VERSION 1 #define SETTINGS_MIN_VERSION 1 #define SETTINGS_FILENAME "mpegplayer.cfg" +const unsigned char rockbox91x32[] = { + 0x00, 0x02, 0x7f, 0x02, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xfa, 0xf8, 0xf8, 0xf0, + 0xe0, 0x80, 0x00, 0x00, 0x80, 0xe0, 0xf0, 0xf0, 0xf8, 0xfa, 0xfa, 0xf4, 0xf4, + 0xe8, 0x90, 0x60, 0x80, 0x60, 0x90, 0xe8, 0xf4, 0xf4, 0xfa, 0xfa, 0xfa, 0xfa, + 0xf4, 0xe8, 0x04, 0xf4, 0xf4, 0xf4, 0x04, 0xfe, 0x04, 0xc0, 0xf0, 0xf4, 0xf4, + 0x34, 0x1e, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x70, 0x88, 0xf0, 0x00, 0xff, 0xff, 0xff, 0xff, 0x02, 0xc2, 0x3c, 0xc3, 0xff, + 0xff, 0xff, 0x00, 0xfe, 0xff, 0xff, 0x07, 0x01, 0x00, 0xfe, 0x02, 0xfd, 0x07, + 0xff, 0xff, 0xfe, 0x01, 0xfe, 0xff, 0xff, 0x0f, 0x01, 0x00, 0x80, 0x00, 0x01, + 0x03, 0x0f, 0x00, 0xff, 0xff, 0xff, 0xc0, 0xf9, 0xfe, 0xff, 0xff, 0x07, 0x04, + 0x04, 0x04, 0xfc, 0x80, 0x40, 0x40, 0x40, 0x40, 0x40, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x80, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x40, 0x40, + 0x40, 0x40, 0x80, 0x00, 0x80, 0x40, 0x80, 0x40, 0x40, 0x40, 0x40, 0xc0, 0x00, + + 0x00, 0x7c, 0xc3, 0x9e, 0x67, 0x37, 0x8f, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff, + 0xe3, 0x80, 0x00, 0xff, 0xff, 0xff, 0xc0, 0x00, 0x01, 0x03, 0xc1, 0x3f, 0xc1, + 0xff, 0xff, 0xff, 0x01, 0xff, 0xff, 0xff, 0xc1, 0x01, 0x01, 0xff, 0x01, 0x00, + 0x00, 0xc0, 0x00, 0xff, 0xff, 0xff, 0xcf, 0x3f, 0xff, 0xf8, 0xff, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x10, 0x08, 0x18, 0xe8, 0x10, 0xe0, 0x00, 0x01, 0x02, 0x04, + 0x02, 0x01, 0xe0, 0x10, 0x08, 0x08, 0x18, 0xe8, 0x10, 0xe0, 0x00, 0x01, 0x00, + 0x00, 0xe0, 0x40, 0x01, 0x02, 0x01, 0x40, 0xe0, 0x18, 0xe4, 0x1b, 0x04, 0x03, + + 0x00, 0x00, 0x00, 0x00, 0x77, 0x6e, 0x61, 0x7f, 0x40, 0xff, 0x00, 0x07, 0x1f, + 0x3f, 0x7f, 0x7c, 0x71, 0xcf, 0x5f, 0x3f, 0x7e, 0x7c, 0x7d, 0x7d, 0x7e, 0x3f, + 0x1f, 0x0f, 0x01, 0x00, 0x41, 0x47, 0x5f, 0x7f, 0x7e, 0x7c, 0x7f, 0x7c, 0x7e, + 0x3f, 0x1f, 0x00, 0x7f, 0x7f, 0x7f, 0x01, 0x4e, 0x71, 0xcf, 0x7f, 0x40, 0x40, + 0x40, 0x40, 0x60, 0x21, 0x42, 0x43, 0x42, 0x41, 0x40, 0x20, 0x10, 0x08, 0x04, + 0x08, 0x10, 0x20, 0x41, 0x42, 0x42, 0x43, 0x42, 0x41, 0x40, 0x60, 0x50, 0x40, + 0x40, 0x40, 0x20, 0x50, 0x28, 0x10, 0x20, 0x40, 0x43, 0x44, 0x5b, 0x64, 0x18, +}; + +#define LOGO rockbox91x32 +#define LOGO_WIDTH 91 +#define LOGO_HEIGHT 32 + +enum sliderState_t {state0, state1, state2, state3, state4, state5} sliderState; +volatile long thumbDelayTimer; + +/* button definitions */ +#if (CONFIG_KEYPAD == IRIVER_H100_PAD) || (CONFIG_KEYPAD == IRIVER_H300_PAD) +#define MPEG_SELECT BUTTON_PLAY +#define MPEG_RIGHT BUTTON_RIGHT +#define MPEG_LEFT BUTTON_LEFT +#define MPEG_SCROLL_DOWN BUTTON_SCROLL_UP +#define MPEG_SCROLL_UP BUTTON_SCROLL_DOWN +#define MPEG_EXIT BUTTON_POWER + +#elif (CONFIG_KEYPAD == IPOD_3G_PAD) || (CONFIG_KEYPAD == IPOD_4G_PAD) +#define MPEG_SELECT BUTTON_SELECT +#define MPEG_RIGHT BUTTON_RIGHT +#define MPEG_LEFT BUTTON_LEFT +#define MPEG_SCROLL_DOWN BUTTON_SCROLL_BACK +#define MPEG_SCROLL_UP BUTTON_SCROLL_FWD +#define MPEG_EXIT BUTTON_MENU + +#elif CONFIG_KEYPAD == GIGABEAT_PAD +#define MPEG_SELECT BUTTON_SELECT +#define MPEG_LEFT BUTTON_LEFT +#define MPEG_RIGHT BUTTON_RIGHT +#define MPEG_SCROLL_DOWN BUTTON_VOL_DOWN +#define MPEG_SCROLL_UP BUTTON_VOL_UP +#define MPEG_EXIT BUTTON_POWER + +#elif CONFIG_KEYPAD == IRIVER_H10_PAD +#define MPEG_SELECT BUTTON_PLAY +#define MPEG_SCROLL_UP BUTTON_SCROLL_UP +#define MPEG_SCROLL_DOWN BUTTON_SCROLL_DOWN +#define MPEG_LEFT BUTTON_LEFT +#define MPEG_RIGHT BUTTON_RIGHT +#define MPEG_EXIT BUTTON_POWER + +#elif CONFIG_KEYPAD == SANSA_E200_PAD +#define MPEG_SELECT BUTTON_SELECT +#define MPEG_SCROLL_UP BUTTON_SCROLL_UP +#define MPEG_SCROLL_DOWN BUTTON_SCROLL_DOWN +#define MPEG_LEFT BUTTON_LEFT +#define MPEG_RIGHT BUTTON_RIGHT +#define MPEG_EXIT BUTTON_POWER + +#else +#error MPEGPLAYER: Unsupported keypad +#endif + static char* showfps_options[] = {"No", "Yes"}; static char* limitfps_options[] = {"No", "Yes"}; static char* skipframes_options[] = {"No", "Yes"}; @@ -22,8 +111,244 @@ {TYPE_ENUM, 0, 2, &settings.showfps, "Show FPS", showfps_options, NULL}, {TYPE_ENUM, 0, 2, &settings.limitfps, "Limit FPS", limitfps_options, NULL}, {TYPE_ENUM, 0, 2, &settings.skipframes, "Skip frames", skipframes_options, NULL}, + {TYPE_STRING, 0, 64, NULL, "Resume 0 Name", NULL, (char*)&settings.resume[0].filename}, + {TYPE_INT, 0, 1024, &settings.resume[0].time, "Resume 0 Time", NULL, NULL}, + {TYPE_STRING, 0, 64, NULL, "Resume 1 Name", NULL, (char*)&settings.resume[1].filename}, + {TYPE_INT, 0, 1024, &settings.resume[1].time, "Resume 1 Time", NULL, NULL}, + {TYPE_STRING, 0, 64, NULL, "Resume 2 Name", NULL, (char*)&settings.resume[2].filename}, + {TYPE_INT, 0, 1024, &settings.resume[2].time, "Resume 2 Time", NULL, NULL}, + {TYPE_INT, 0, 2, &settings.oldest_resume, "Oldest resume", NULL, NULL}, }; +int get_resume_time(char* filename) +{ + int i; + for (i=0; istrcmp(settings.resume[i].filename, filename) == 0) + return settings.resume[i].time; + + return 0; +} + +void store_resume_info(char* filename, int time) +{ + int i; + int found = 0; + + for(i=0; istrcmp(settings.resume[i].filename, filename) == 0) + { + settings.resume[i].time = time; + found = 1; + if (settings.oldest_resume == i) + settings.oldest_resume = (i+1)%MAX_RESUME; + } + } + + if (!found) + { + rb->strcpy(settings.resume[settings.oldest_resume].filename, filename); + settings.resume[settings.oldest_resume].time = time; + settings.oldest_resume = (settings.oldest_resume+1)%MAX_RESUME; + } +} + +int get_start_time(int resume_time, int end_time, int in_file) +{ + int quit = 0; + int button = 0; + char resume_str[32]; + + int preview_height = 90; + int preview_width = 114; + int preview_ypos = (LCD_HEIGHT/2)-(preview_height/2)-8; + int preview_xpos = (LCD_WIDTH/2)-(preview_width/2); + + float slider_margin = LCD_WIDTH*0.1; + float slider_width = LCD_WIDTH-(2*slider_margin); + float slider_fill_rate = slider_width/end_time; + int slider_ypos = preview_ypos+preview_height+8; + int seek_rtn; + + sliderState = state0; + thumbDelayTimer = *(rb->current_tick); + rb->lcd_mono_bitmap(LOGO, + preview_xpos+((preview_width-LOGO_WIDTH)/2), + preview_ypos+((preview_height-LOGO_HEIGHT)/2), + LOGO_WIDTH, LOGO_HEIGHT); + rb->lcd_drawrect(preview_xpos, preview_ypos, preview_width, preview_height); + rb->lcd_update_rect(preview_xpos, preview_ypos, preview_width, preview_height); + + while(quit == 0) + { + button = rb->button_get(false); + switch (button) + { + case MPEG_SCROLL_UP: + case MPEG_SCROLL_UP | BUTTON_REPEAT: + case MPEG_LEFT: + case MPEG_LEFT | BUTTON_REPEAT: + if (--resume_time < 0) + resume_time = 0; + sliderState = state0; + thumbDelayTimer = *(rb->current_tick); + break; + case MPEG_SCROLL_DOWN: + case MPEG_SCROLL_DOWN | BUTTON_REPEAT: + case MPEG_RIGHT: + case MPEG_RIGHT | BUTTON_REPEAT: + if (++resume_time > end_time) + resume_time = end_time; + sliderState = state0; + thumbDelayTimer = *(rb->current_tick); + break; + case MPEG_SELECT: + quit = 1; + break; + case MPEG_EXIT: + resume_time = -1; + quit = 1; + break; + default: + if (rb->default_event_handler(button) == SYS_USB_CONNECTED) + { + resume_time = -1; + quit = 1; + } + break; + } + + rb->yield(); + + if (sliderState == state0) { + rb->splash(0, "loading ..."); + sliderState = state1; + } + + if (sliderState == state1) { + if (*(rb->current_tick) - thumbDelayTimer > 75) + sliderState = state2; + if (resume_time == 0) { + seek_rtn = 0; + rb->lcd_mono_bitmap(LOGO, + preview_xpos+((preview_width-LOGO_WIDTH)/2), + preview_ypos+((preview_height-LOGO_HEIGHT)/2), + LOGO_WIDTH, LOGO_HEIGHT); + rb->lcd_drawrect(preview_xpos, preview_ypos, preview_width, preview_height); + rb->lcd_update_rect(preview_xpos, preview_ypos, preview_width, preview_height); + sliderState = state5; + } + rb->lcd_set_foreground(LCD_BLACK); + rb->lcd_fillrect(0, slider_ypos, LCD_WIDTH, LCD_HEIGHT-slider_ypos-1); + rb->lcd_set_foreground(LCD_WHITE); + + rb->snprintf(resume_str, sizeof(resume_str), "%u", 0); + rb->lcd_putsxy(slider_margin, slider_ypos, resume_str); + rb->snprintf(resume_str, sizeof(resume_str), "%u", end_time); + rb->lcd_putsxy(LCD_WIDTH-slider_margin-16, slider_ypos, resume_str); + + rb->lcd_drawrect(slider_margin, slider_ypos+13, slider_width, 8); + rb->lcd_fillrect(slider_margin, slider_ypos+13, slider_fill_rate*resume_time, 8); + + rb->snprintf(resume_str, sizeof(resume_str), "%u", resume_time); + rb->lcd_putsxy(slider_margin+(slider_fill_rate*resume_time-5), slider_ypos+29, resume_str); + + rb->lcd_update_rect(0, slider_ypos, LCD_WIDTH, LCD_HEIGHT-slider_ypos); + } + + if (sliderState == 2) { + if ( (seek_rtn = seek_PTS(in_file, resume_time, 1)) >= 0) + sliderState = state3; + else { + sliderState = 0; + thumbDelayTimer = *(rb->current_tick); + } + } + + if (sliderState == 3) { + display_thumb(in_file); + sliderState = 4; + } + + if (sliderState == 4) { + rb->lcd_set_foreground(LCD_BLACK); + rb->lcd_fillrect(0, slider_ypos, LCD_WIDTH, LCD_HEIGHT-slider_ypos-1); + rb->lcd_set_foreground(LCD_WHITE); + + rb->snprintf(resume_str, sizeof(resume_str), "%u", 0); + rb->lcd_putsxy(slider_margin, slider_ypos, resume_str); + rb->snprintf(resume_str, sizeof(resume_str), "%u", end_time); + rb->lcd_putsxy(LCD_WIDTH-slider_margin-16, slider_ypos, resume_str); + + rb->lcd_drawrect(slider_margin, slider_ypos+13, slider_width, 8); + rb->lcd_fillrect(slider_margin, slider_ypos+13, slider_fill_rate*resume_time, 8); + + rb->snprintf(resume_str, sizeof(resume_str), "%u", resume_time); + rb->lcd_putsxy(slider_margin+(slider_fill_rate*resume_time-5), slider_ypos+29, resume_str); + + rb->lcd_update_rect(0, slider_ypos, LCD_WIDTH, LCD_HEIGHT-slider_ypos); + sliderState = 5; + } + } + + return resume_time; +} + +int mpeg_start_menu(char* filename, int end_time, int in_file) +{ + int m; + int result = 0; + int menu_quit = 0; + + // add the resume time to the menu display + int resume_time = get_resume_time(filename); + char resume_str[32]; + rb->snprintf(resume_str, sizeof(resume_str), "Resume time (min): %u", resume_time); + + struct menu_item items[] = { + { "Play from beginning", NULL }, + { resume_str, NULL }, + { "Set start time (min)", NULL }, + }; + + m = menu_init(rb, items, sizeof(items) / sizeof(*items), + NULL, NULL, NULL, NULL); + + rb->button_clear_queue(); + + while(menu_quit == 0) { + result = menu_show(m); + + switch (result) + { + case 0: + menu_quit = 1; + result = 0; + break; + case 1: + menu_quit = 1; + result = resume_time; + break; + case 2: + if ((result = get_start_time(resume_time, end_time, in_file)) >= 0) + menu_quit = 1; + break; + default: + if (result == MENU_ATTACHED_USB) + { + menu_quit = 1; + result = -1; + } + break; + } + } + menu_exit(m); + + store_resume_info(filename, result); + return (int)result; +} + bool mpeg_menu(void) { int m; @@ -84,12 +409,20 @@ void init_settings(void) { /* Set the default settings */ + int i; settings.showfps = 0; /* Do not show FPS */ settings.limitfps = 1; /* Limit FPS */ settings.skipframes = 1; /* Skip frames */ + for (i=0; i= LCD_HEIGHT + for (r=0;r= LCD_HEIGHT + yuv_bitmap_part(tmpbuf,0,0,image_width/2,(LCD_WIDTH-image_width/2)/2, + (LCD_HEIGHT-image_height/2)/2-8,output_width/2,output_height/2); + + rb->lcd_update_rect(output_x,output_y,output_width,output_height); +#else + yuv_bitmap_part(tmpbuf,0,0,image_height/2,(LCD_HEIGHT-image_height/2)/2-8, + (LCD_WIDTH-image_width/2)/2,output_height/2,output_width/2); + + rb->lcd_update_rect(output_y,output_x,output_height,output_width); +#endif +#else +#if LCD_WIDTH >= LCD_HEIGHT + rb->lcd_yuv_blit(tmpbuf,0,0,image_width/2,(LCD_WIDTH-image_width/2)/2, + (LCD_HEIGHT-image_height/2)/2-8,output_width/2,output_height/2); +#else + rb->lcd_yuv_blit(tmpbuf,0,0,image_height/2,(LCD_HEIGHT-image_height/2)/2-8, + (LCD_WIDTH-image_width/2)/2,output_height/2,output_width/2); +#endif +#endif +#else +#if LCD_WIDTH >= LCD_HEIGHT + gray_ub_gray_bitmap_part(tmpbuf[0],0,0,image_width/2,(LCD_WIDTH-image_width/2)/2, + (LCD_HEIGHT-image_height/2)/2-8,output_width/2,output_height/2); +#else + gray_ub_gray_bitmap_part(tmpbuf[0],0,0,image_height/2,(LCD_HEIGHT-image_height/2)/2-8, + (LCD_WIDTH-image_width/2)/2,output_height/2,output_width/2); +#endif +#endif +} + void vo_setup(const mpeg2_sequence_t * sequence) { image_width=sequence->width; diff --exclude=.svn -Naur rockbox_svn_2007-07-25/firmware/drivers/button.c rockbox/firmware/drivers/button.c --- rockbox_svn_2007-07-25/firmware/drivers/button.c 2007-07-25 13:53:12.000000000 -0400 +++ rockbox/firmware/drivers/button.c 2007-07-26 13:06:07.000000000 -0400 @@ -287,6 +287,11 @@ } #endif /* HAVE_ADJUSTABLE_CPU_FREQ */ +int button_available( void ) +{ + return queue_count(&button_queue); +} + long button_get(bool block) { struct event ev; diff --exclude=.svn -Naur rockbox_svn_2007-07-25/firmware/export/button.h rockbox/firmware/export/button.h --- rockbox_svn_2007-07-25/firmware/export/button.h 2007-07-25 13:53:08.000000000 -0400 +++ rockbox/firmware/export/button.h 2007-07-25 13:54:49.000000000 -0400 @@ -27,6 +27,7 @@ extern struct event_queue button_queue; void button_init (void); +int button_available(void); long button_get (bool block); long button_get_w_tmo(int ticks); intptr_t button_get_data(void); diff --exclude=.svn -Naur rockbox_svn_2007-07-25/uisimulator/sdl/button.c rockbox/uisimulator/sdl/button.c --- rockbox_svn_2007-07-25/uisimulator/sdl/button.c 2007-07-25 13:53:39.000000000 -0400 +++ rockbox/uisimulator/sdl/button.c 2007-07-26 13:06:42.000000000 -0400 @@ -695,6 +695,11 @@ /* Again copied from real button.c... */ +int button_available( void ) +{ + return queue_count(&button_queue); +} + long button_get(bool block) { struct event ev;