Ticket #11609: 0001-Implement-DVD-bookmarks-by-saving-and-restoring-the-.patch
File 0001-Implement-DVD-bookmarks-by-saving-and-restoring-the-.patch, 29.8 KB (added by , 8 years ago) |
---|
-
mythtv/libs/libmyth/programinfo.cpp
From db65cca9fc4dfe0bd29018b43995ca8c56b18fbf Mon Sep 17 00:00:00 2001 From: Richard <peper03@yahoo.com> Date: Tue, 18 Jun 2013 22:44:47 +0200 Subject: [PATCH] Implement DVD bookmarks by saving and restoring the full DVD VM's state to make playback from bookmarks more reliable for all DVDs. The state snapshot code is borrowed/adapted from or inspired by XBMC and Ogle. Existing bookmarks are supported but will be converted if stored again. --- mythtv/libs/libmyth/programinfo.cpp | 67 +++--- mythtv/libs/libmythbase/mythversion.h | 2 +- mythtv/libs/libmythdvdnav/dvdnav/dvdnav.c | 58 ++++++ mythtv/libs/libmythdvdnav/dvdnav/dvdnav.h | 15 ++ mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c | 57 ++++++ mythtv/libs/libmythdvdnav/dvdnav/vm/vm.h | 2 + mythtv/libs/libmythdvdnav/dvdnav/vm/vm_serialize.c | 215 ++++++++++++++++++++ mythtv/libs/libmythdvdnav/dvdnav/vm/vm_serialize.h | 9 + mythtv/libs/libmythdvdnav/libmythdvdnav.pro | 6 +- mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp | 25 +++ mythtv/libs/libmythtv/DVD/dvdringbuffer.h | 2 + mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp | 139 +++++++------ mythtv/libs/libmythtv/DVD/mythdvdplayer.h | 3 +- mythtv/libs/libmythtv/dbcheck.cpp | 11 + mythtv/programs/mythfrontend/main.cpp | 12 +- 15 files changed, 518 insertions(+), 105 deletions(-) create mode 100644 mythtv/libs/libmythdvdnav/dvdnav/vm/vm_serialize.c create mode 100644 mythtv/libs/libmythdvdnav/dvdnav/vm/vm_serialize.h diff --git a/mythtv/libs/libmyth/programinfo.cpp b/mythtv/libs/libmyth/programinfo.cpp index f59cf4a..f0d4102 100644
a b QStringList ProgramInfo::QueryDVDBookmark( 2579 2579 2580 2580 if (!(programflags & FL_IGNOREBOOKMARK)) 2581 2581 { 2582 query.prepare(" SELECT title, framenum, audionum, subtitlenum "2582 query.prepare(" SELECT dvdstate, title, framenum, audionum, subtitlenum " 2583 2583 " FROM dvdbookmark " 2584 2584 " WHERE serialid = :SERIALID "); 2585 2585 query.bindValue(":SERIALID", serialid); 2586 2586 2587 2587 if (query.exec() && query.next()) 2588 2588 { 2589 for(int i = 0; i < 4; i++) 2590 fields.append(query.value(i).toString()); 2589 QString dvdstate = query.value(0).toString(); 2590 2591 if (!dvdstate.isEmpty()) 2592 { 2593 fields.append(dvdstate); 2594 } 2595 else 2596 { 2597 // Legacy bookmark 2598 for(int i = 1; i < 5; i++) 2599 fields.append(query.value(i).toString()); 2600 } 2591 2601 } 2592 2602 } 2593 2603 … … void ProgramInfo::SaveDVDBookmark(const QStringList &fields) const 2601 2611 2602 2612 QString serialid = *(it); 2603 2613 QString name = *(++it); 2604 QString title = *(++it);2605 QString audionum = *(++it);2606 QString subtitlenum = *(++it);2607 QString frame = *(++it);2608 2614 2609 query.prepare("INSERT IGNORE INTO dvdbookmark " 2610 " (serialid, name)" 2611 " VALUES ( :SERIALID, :NAME );"); 2612 query.bindValue(":SERIALID", serialid); 2613 query.bindValue(":NAME", name); 2615 if( fields.count() == 3 ) 2616 { 2617 // We have a state field, so update/create the bookmark 2618 QString state = *(++it); 2614 2619 2615 if (!query.exec()) 2616 MythDB::DBError("SetDVDBookmark inserting", query); 2617 2618 query.prepare(" UPDATE dvdbookmark " 2619 " SET title = :TITLE , " 2620 " audionum = :AUDIONUM , " 2621 " subtitlenum = :SUBTITLENUM , " 2622 " framenum = :FRAMENUM , " 2623 " timestamp = NOW() " 2624 " WHERE serialid = :SERIALID"); 2625 query.bindValue(":TITLE",title); 2626 query.bindValue(":AUDIONUM",audionum); 2627 query.bindValue(":SUBTITLENUM",subtitlenum); 2628 query.bindValue(":FRAMENUM",frame); 2629 query.bindValue(":SERIALID",serialid); 2620 query.prepare("INSERT IGNORE INTO dvdbookmark " 2621 " (serialid, name)" 2622 " VALUES ( :SERIALID, :NAME );"); 2623 query.bindValue(":SERIALID", serialid); 2624 query.bindValue(":NAME", name); 2625 2626 if (!query.exec()) 2627 MythDB::DBError("SetDVDBookmark inserting", query); 2628 2629 query.prepare(" UPDATE dvdbookmark " 2630 " SET dvdstate = :STATE , " 2631 " timestamp = NOW() " 2632 " WHERE serialid = :SERIALID"); 2633 query.bindValue(":STATE",state); 2634 query.bindValue(":SERIALID",serialid); 2635 } 2636 else 2637 { 2638 // No state field, delete the bookmark 2639 query.prepare("DELETE FROM dvdbookmark " 2640 "WHERE serialid = :SERIALID"); 2641 query.bindValue(":SERIALID",serialid); 2642 } 2630 2643 2631 2644 if (!query.exec()) 2632 2645 MythDB::DBError("SetDVDBookmark updating", query); -
mythtv/libs/libmythbase/mythversion.h
diff --git a/mythtv/libs/libmythbase/mythversion.h b/mythtv/libs/libmythbase/mythversion.h index c485b9b..dc53fc5 100644
a b 61 61 * mythtv/bindings/php/MythBackend.php 62 62 #endif 63 63 64 #define MYTH_DATABASE_VERSION "131 2"64 #define MYTH_DATABASE_VERSION "1313" 65 65 66 66 67 67 MBASE_PUBLIC const char *GetMythSourceVersion(); -
mythtv/libs/libmythdvdnav/dvdnav/dvdnav.c
diff --git a/mythtv/libs/libmythdvdnav/dvdnav/dvdnav.c b/mythtv/libs/libmythdvdnav/dvdnav/dvdnav.c index 4fe270b..3a7952e 100644
a b user_ops_t dvdnav_get_restrictions(dvdnav_t* this) { 1224 1224 1225 1225 return ops.ops_struct; 1226 1226 } 1227 1228 char* dvdnav_get_state(dvdnav_t *this) 1229 { 1230 char *state = NULL; 1231 1232 if(this && this->vm) { 1233 pthread_mutex_lock(&this->vm_lock); 1234 1235 if( !(state = vm_get_state_str(this->vm)) ) 1236 printerr("Failed to get vm state."); 1237 1238 pthread_mutex_unlock(&this->vm_lock); 1239 } 1240 1241 return state; 1242 } 1243 1244 dvdnav_status_t dvdnav_set_state(dvdnav_t *this, const char *state_str) 1245 { 1246 if(!this || !this->vm) 1247 { 1248 printerr("Passed a NULL pointer."); 1249 return DVDNAV_STATUS_ERR; 1250 } 1251 1252 if(!this->started) { 1253 printerr("Virtual DVD machine not started."); 1254 return DVDNAV_STATUS_ERR; 1255 } 1256 1257 pthread_mutex_lock(&this->vm_lock); 1258 1259 /* reset the dvdnav state */ 1260 memset(&this->pci,0,sizeof(this->pci)); 1261 memset(&this->dsi,0,sizeof(this->dsi)); 1262 this->last_cmd_nav_lbn = SRI_END_OF_CELL; 1263 1264 /* Set initial values of flags */ 1265 this->position_current.still = 0; 1266 this->skip_still = 0; 1267 this->sync_wait = 0; 1268 this->sync_wait_skip = 0; 1269 this->spu_clut_changed = 0; 1270 1271 1272 /* set the state. this will also start the vm on that state */ 1273 /* means the next read block should be comming from that new */ 1274 /* state */ 1275 if( !vm_set_state(this->vm, state_str) ) 1276 { 1277 printerr("Failed to set vm state."); 1278 pthread_mutex_unlock(&this->vm_lock); 1279 return DVDNAV_STATUS_ERR; 1280 } 1281 1282 pthread_mutex_unlock(&this->vm_lock); 1283 return DVDNAV_STATUS_OK; 1284 } -
mythtv/libs/libmythdvdnav/dvdnav/dvdnav.h
diff --git a/mythtv/libs/libmythdvdnav/dvdnav/dvdnav.h b/mythtv/libs/libmythdvdnav/dvdnav/dvdnav.h index 04fe99a..1e7fa08 100644
a b int8_t dvdnav_is_domain_vtsm(dvdnav_t *self); 726 726 */ 727 727 int8_t dvdnav_is_domain_vts(dvdnav_t *self); 728 728 729 /********************************************************************* 730 * Save/restore playback state * 731 *********************************************************************/ 732 733 /* 734 * Get a text string representing a snapshot of the current internal state 735 * The calling application is responsible for freeing the returned buffer. 736 */ 737 char* dvdnav_get_state(dvdnav_t *self); 738 739 /* 740 * Set the current internal state to an earlier snapshot 741 */ 742 dvdnav_status_t dvdnav_set_state(dvdnav_t *self, const char *state_str); 743 729 744 730 745 #ifdef __cplusplus 731 746 } -
mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c
diff --git a/mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c b/mythtv/libs/libmythdvdnav/dvdnav/vm/vm.c index 24e6fd8..7b8f401 100644
a b 45 45 #include "decoder.h" 46 46 #include "remap.h" 47 47 #include "vm.h" 48 #include "vm_serialize.h" 48 49 #include "dvdnav_internal.h" 49 50 50 51 #ifdef _MSC_VER … … void vm_ifo_close(ifo_handle_t *ifo) 2017 2018 ifoClose(ifo); 2018 2019 } 2019 2020 2021 char *vm_get_state_str(vm_t *vm) { 2022 char *str_state = NULL; 2023 2024 if(vm) 2025 str_state = vm_serialize_dvd_state(&vm->state); 2026 2027 return str_state; 2028 } 2029 2030 int vm_set_state(vm_t *vm, const char *state_str) { 2031 /* restore state from save_state as taken from ogle */ 2032 2033 dvd_state_t save_state; 2034 2035 if(state_str == NULL) { 2036 return 0; 2037 } 2038 2039 if(!vm_deserialize_dvd_state(state_str, &save_state)) { 2040 #ifdef TRACE 2041 fprintf( MSG_OUT, "state_str invalid\n"); 2042 #endif 2043 return 0; 2044 } 2045 2046 /* open the needed vts */ 2047 if( !ifoOpenNewVTSI(vm, vm->dvd, save_state.vtsN) ) return 0; 2048 // sets state.vtsN 2049 2050 vm->state = save_state; 2051 /* set state.domain before calling */ 2052 //calls get_pgcit() 2053 // needs state.domain and sprm[0] set 2054 // sets pgcit depending on state.domain 2055 //writes: state.pgc 2056 // state.pgN 2057 // state.TT_PGCN_REG 2058 2059 if( !set_PGCN(vm, save_state.pgcN) ) return 0; 2060 save_state.pgc = vm->state.pgc; 2061 2062 /* set the rest of state after the call */ 2063 vm->state = save_state; 2064 2065 /* if we are not in standard playback, we must get all data */ 2066 /* otherwise we risk loosing stillframes, and overlays */ 2067 if(vm->state.domain != VTS_DOMAIN) 2068 vm->state.blockN = 0; 2069 2070 /* force a flush of data here */ 2071 /* we don't need a hop seek here as it's a complete state*/ 2072 vm->hop_channel++; 2073 2074 return 1; 2075 } 2076 2020 2077 /* Debug functions */ 2021 2078 2022 2079 #ifdef TRACE -
mythtv/libs/libmythdvdnav/dvdnav/vm/vm.h
diff --git a/mythtv/libs/libmythdvdnav/dvdnav/vm/vm.h b/mythtv/libs/libmythdvdnav/dvdnav/vm/vm.h index d94b3c1..3daf421 100644
a b audio_attr_t vm_get_audio_attr(vm_t *vm, int streamN); 171 171 subp_attr_t vm_get_subp_attr(vm_t *vm, int streamN); 172 172 ifo_handle_t *vm_get_title_ifo(vm_t *vm, uint32_t title); 173 173 void vm_ifo_close(ifo_handle_t *ifo); 174 char *vm_get_state_str(vm_t *vm); 175 int vm_set_state(vm_t *vm, const char *state_str); 174 176 175 177 /* Uncomment for VM command tracing */ 176 178 /* #define TRACE */ -
new file mythtv/libs/libmythdvdnav/dvdnav/vm/vm_serialize.c
diff --git a/mythtv/libs/libmythdvdnav/dvdnav/vm/vm_serialize.c b/mythtv/libs/libmythdvdnav/dvdnav/vm/vm_serialize.c new file mode 100644 index 0000000..a4d201a
- + 1 #include <stdio.h> 2 #include <unistd.h> 3 #include <inttypes.h> 4 5 6 #include <dvdread/nav_types.h> 7 #include <dvdread/ifo_types.h> 8 #include <dvdread/ifo_read.h> 9 #include "dvdnav/dvdnav.h" 10 #include "remap.h" 11 #include "decoder.h" 12 #include "vm.h" 13 14 /* 15 "navstate",<version>,<sprm x 24>,<gprm x 16>, 16 <domain>,<vtsn>,<pgcn>,<pgn>,<celln>,<cell_restart>,<blockn>, 17 <rsm_vts>,<rsm_blockn>,<rsm_pgcn>,<rsm_celln>,<rsm_sprm x 5>,"end" 18 */ 19 /* The serialized string starts with "navstate,1,", so that needs 11 chars. 20 * There are 10 integer fields (domain, vtsN, pgcN, pgN, cellN, cell_restart, 21 * blockN, rsm_vtsN, rsm_blockN, rsm_pgcN and rsm_cellN). 22 * None of the values can realistically be more than 32 bits (and most will 23 * be far less). In worst case, each field would need 11 characters 24 * (-2147483648) plus a trailing comma, so we need 10 * (11+1) = 120 chars 25 * for those 10 fields. 26 * Each SPRM is 16 bits, so thats 6 chars + 1 per register ("0xffff,") * 24 27 * registers = 168 chars. 28 * Each GPRM is 16 bits plus a mode character plus two 32 bit counter values. 29 * In the format "[0xffff;0;0xffffffff;0xffffffff],", each register needs 33 30 * chars. With 16 registers, that's 33 * 16 = 528 31 * There are five resume SPRM values, so 5 * (6 + !) = 42 32 * Finally, the string is terminated with "end" and a NULL char, so another 4 chars. 33 * In total then, 11 + 120 + 168 + 528 + 42 + 4 = 873 chars. Round that up to 1024 34 * and there should never be any issues. Just to be safe, we'll still check as 35 * we go along. 36 */ 37 38 #define BUFFER_SIZE 1024 39 #define FORMAT_VERSION 1 40 41 static void vm_serialize_int(int *stored, char **buf, size_t *remaining, int value) 42 { 43 if(stored && buf && remaining && *stored > 0) 44 { 45 *stored = snprintf(*buf, *remaining, "%d,", value); 46 if(*stored > 0) 47 { 48 *remaining -= (size_t)(*stored); 49 *buf += (*stored); 50 } 51 } 52 } 53 54 static void vm_deserialize_int(int *consumed, char **buf, int* value) 55 { 56 if(consumed && buf && *consumed > 0) 57 { 58 sscanf( *buf, "%d,%n", value, consumed); 59 60 if(*consumed > 0) 61 *buf += *consumed; 62 } 63 } 64 65 char *vm_serialize_dvd_state(const dvd_state_t *state) 66 { 67 char *str_state = 0; 68 char *buf; 69 int stored; 70 int tmp; 71 int idx; 72 size_t remaining = BUFFER_SIZE; 73 74 if(state) 75 { 76 str_state = malloc(BUFFER_SIZE); 77 buf = str_state; 78 79 stored = snprintf(buf, remaining, "navstat,%d,", FORMAT_VERSION); 80 81 if(stored > 0) 82 { 83 remaining -= (size_t)stored; 84 buf += stored; 85 } 86 87 // SPRM 88 for(idx = 0; idx < 24 && stored > 0; idx++) 89 { 90 stored = snprintf(buf, remaining, "0x%hx,", state->registers.SPRM[idx]); 91 if(stored > 0) 92 { 93 remaining -= (size_t)stored; 94 buf += stored; 95 } 96 } 97 98 // GPRM 99 for(idx = 0; idx < 16 && stored > 0; idx++) 100 { 101 stored = snprintf(buf, remaining, 102 "[0x%hx;%d;0x%x;0x%x],", state->registers.GPRM[idx], 103 state->registers.GPRM_mode[idx], 104 state->registers.GPRM_time[idx].tv_sec, 105 state->registers.GPRM_time[idx].tv_usec); 106 if(stored > 0) 107 { 108 remaining -= (size_t)stored; 109 buf += stored; 110 } 111 } 112 113 vm_serialize_int(&stored, &buf, &remaining, state->domain); 114 vm_serialize_int(&stored, &buf, &remaining, state->vtsN); 115 vm_serialize_int(&stored, &buf, &remaining, state->pgcN); 116 vm_serialize_int(&stored, &buf, &remaining, state->pgN); 117 vm_serialize_int(&stored, &buf, &remaining, state->cellN); 118 vm_serialize_int(&stored, &buf, &remaining, state->cell_restart); 119 vm_serialize_int(&stored, &buf, &remaining, state->blockN); 120 vm_serialize_int(&stored, &buf, &remaining, state->rsm_vtsN); 121 vm_serialize_int(&stored, &buf, &remaining, state->rsm_blockN); 122 vm_serialize_int(&stored, &buf, &remaining, state->rsm_pgcN); 123 vm_serialize_int(&stored, &buf, &remaining, state->rsm_cellN); 124 125 // Resume SPRM 126 for(idx = 0; idx < 5 && stored > 0; idx++) 127 { 128 stored = snprintf(buf, remaining, "0x%hx,", state->rsm_regs[idx]); 129 if(stored > 0) 130 { 131 remaining -= (size_t)stored; 132 buf += stored; 133 } 134 } 135 136 if(stored > 0 && remaining >= 4) 137 { 138 // Done. Terminating the string. 139 strcpy(buf, "end"); 140 } 141 else 142 { 143 // Error 144 free(str_state); 145 str_state = 0; 146 } 147 } 148 return str_state; 149 } 150 151 int vm_deserialize_dvd_state(const char* serialized, dvd_state_t *state) 152 { 153 char *buf = serialized; 154 int consumed; 155 int version; 156 int tmp; 157 int idx; 158 int ret = 0; /* assume an error */ 159 dvd_state_t new_state; 160 161 sscanf( buf, "navstat,%d,%n", &version, &consumed); 162 if(version == 1) 163 { 164 buf += consumed; 165 166 // SPRM 167 for(idx = 0; idx < 24 && consumed > 0; idx++) 168 { 169 sscanf(buf, "0x%hx,%n", &new_state.registers.SPRM[idx], &consumed); 170 buf += consumed; 171 } 172 173 // GPRM 174 for(idx = 0; idx < 16 && consumed > 0; idx++) 175 { 176 sscanf(buf, "[0x%hx;%d;0x%x;0x%x],%n", &new_state.registers.GPRM[idx], 177 &new_state.registers.GPRM_mode[idx], 178 &new_state.registers.GPRM_time[idx].tv_sec, 179 &new_state.registers.GPRM_time[idx].tv_usec, 180 &consumed); 181 buf += consumed; 182 } 183 184 vm_deserialize_int(&consumed, &buf, &new_state.domain); 185 vm_deserialize_int(&consumed, &buf, &new_state.vtsN); 186 vm_deserialize_int(&consumed, &buf, &new_state.pgcN); 187 vm_deserialize_int(&consumed, &buf, &new_state.pgN); 188 vm_deserialize_int(&consumed, &buf, &new_state.cellN); 189 vm_deserialize_int(&consumed, &buf, &tmp); 190 new_state.cell_restart = tmp; 191 vm_deserialize_int(&consumed, &buf, &new_state.blockN); 192 vm_deserialize_int(&consumed, &buf, &new_state.rsm_vtsN); 193 vm_deserialize_int(&consumed, &buf, &new_state.rsm_blockN); 194 vm_deserialize_int(&consumed, &buf, &new_state.rsm_pgcN); 195 vm_deserialize_int(&consumed, &buf, &new_state.rsm_cellN); 196 197 // Resume SPRM 198 for(idx = 0; idx < 5 && consumed > 0; idx++) 199 { 200 sscanf(buf, "0x%hx,%n", &new_state.registers.SPRM[idx], &consumed); 201 buf += consumed; 202 } 203 204 if(strcmp(buf,"end") == 0) 205 { 206 /* Success! */ 207 *state = new_state; 208 state->pgc = NULL; 209 ret = 1; 210 } 211 } 212 213 return ret; 214 } 215 -
new file mythtv/libs/libmythdvdnav/dvdnav/vm/vm_serialize.h
diff --git a/mythtv/libs/libmythdvdnav/dvdnav/vm/vm_serialize.h b/mythtv/libs/libmythdvdnav/dvdnav/vm/vm_serialize.h new file mode 100644 index 0000000..e26e9e0
- + 1 #ifndef LIBDVDNAV_VM_SERIALIZE_H 2 #define LIBDVDNAV_VM_SERIALIZE_H 3 4 #include "vm.h" 5 6 char *vm_serialize_dvd_state(const dvd_state_t *state); 7 int vm_deserialize_dvd_state(const char* serialized, dvd_state_t *state); 8 9 #endif /* LIBDVDNAV_VM_SERIALIZE_H */ -
mythtv/libs/libmythdvdnav/libmythdvdnav.pro
diff --git a/mythtv/libs/libmythdvdnav/libmythdvdnav.pro b/mythtv/libs/libmythdvdnav/libmythdvdnav.pro index d9c01a4..870bdc6 100644
a b DEFINES += HAVE_AV_CONFIG_H 21 21 QMAKE_CLEAN += $(TARGET) $(TARGETA) $(TARGETD) $(TARGET0) $(TARGET1) $(TARGET2) 22 22 23 23 # dvdnav 24 HEADERS += dvdnav/dvdnav_internal.h dvdnav/read_cache.h dvdnav/remap.h 24 HEADERS += dvdnav/dvdnav_internal.h dvdnav/read_cache.h dvdnav/remap.h \ 25 dvdnav/vm/vm_serialize.h 25 26 HEADERS += dvdnav/vm/decoder.h dvdnav/vm/vm.h dvdnav/vm/vmcmd.h 26 27 27 SOURCES += dvdnav/dvdnav.c dvdnav/read_cache.c dvdnav/navigation.c 28 SOURCES += dvdnav/dvdnav.c dvdnav/read_cache.c dvdnav/navigation.c \ 29 dvdnav/vm/vm_serialize.c 28 30 SOURCES += dvdnav/highlight.c dvdnav/searching.c dvdnav/settings.c 29 31 SOURCES += dvdnav/remap.c dvdnav/vm/decoder.c dvdnav/vm/vm.c 30 32 SOURCES += dvdnav/vm/vmcmd.c -
mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp
diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp b/mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp index cb854d7..16b0eb4 100644
a b bool DVDRingBuffer::GetNameAndSerialNum(QString& _name, QString& _serial) 1895 1895 return true; 1896 1896 } 1897 1897 1898 /** \brief Get a snapshot of the current DVD VM state 1899 */ 1900 bool DVDRingBuffer::GetDVDStateSnapshot(QString& state) 1901 { 1902 state.clear(); 1903 char* dvdstate = dvdnav_get_state(m_dvdnav); 1904 1905 if (dvdstate) 1906 { 1907 state = dvdstate; 1908 free(dvdstate); 1909 } 1910 1911 return (!state.isEmpty()); 1912 } 1913 1914 /** \brief Restore a DVD VM from a snapshot 1915 */ 1916 bool DVDRingBuffer::RestoreDVDStateSnapshot(QString& state) 1917 { 1918 QByteArray ba_state = state.toAscii(); 1919 1920 return (dvdnav_set_state(m_dvdnav, ba_state.constData()) == DVDNAV_STATUS_OK); 1921 } 1922 1898 1923 /** \brief used by DecoderBase for the total frame number calculation 1899 1924 * for position map support and ffw/rew. 1900 1925 * FPS for a dvd is determined by AFD::normalized_fps -
mythtv/libs/libmythtv/DVD/dvdringbuffer.h
diff --git a/mythtv/libs/libmythtv/DVD/dvdringbuffer.h b/mythtv/libs/libmythtv/DVD/dvdringbuffer.h index c5e4d36..9e2159f 100644
a b class MTV_PUBLIC DVDRingBuffer : public RingBuffer 132 132 int GetAudioTrackType(uint stream_id); 133 133 134 134 bool GetNameAndSerialNum(QString& _name, QString& _serialnum); 135 bool GetDVDStateSnapshot(QString& state); 136 bool RestoreDVDStateSnapshot(QString& state); 135 137 double GetFrameRate(void); 136 138 bool StartOfTitle(void) { return (m_part == 0); } 137 139 bool EndOfTitle(void) { return ((!m_titleParts) || -
mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp
diff --git a/mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp b/mythtv/libs/libmythtv/DVD/mythdvdplayer.cpp index 34aa40b..82e65a4 100644
a b void MythDVDPlayer::PreProcessNormalFrame(void) 109 109 DisplayDVDButton(); 110 110 } 111 111 112 void MythDVDPlayer::VideoStart(void) 113 { 114 if (!m_initial_dvdstate.isEmpty()) 115 player_ctx->buffer->DVD()->RestoreDVDStateSnapshot(m_initial_dvdstate); 116 117 MythPlayer::VideoStart(); 118 } 119 112 120 bool MythDVDPlayer::VideoLoop(void) 113 121 { 114 122 if (!player_ctx->buffer->IsDVD()) … … void MythDVDPlayer::EventStart(void) 286 294 void MythDVDPlayer::InitialSeek(void) 287 295 { 288 296 player_ctx->buffer->IgnoreWaitStates(true); 297 289 298 if (m_initial_title > -1) 290 299 player_ctx->buffer->DVD()->PlayTitleAndPart(m_initial_title, 1); 291 300 … … void MythDVDPlayer::InitialSeek(void) 298 307 299 308 if (bookmarkseek > 30) 300 309 { 301 302 310 // we need to trigger a dvd cell change to ensure the new title length 303 311 // is set and the position map updated accordingly 304 312 decodeOneFrame = true; … … bool MythDVDPlayer::PrepareAudioSample(int64_t &timecode) 334 342 335 343 void MythDVDPlayer::SetBookmark(bool clear) 336 344 { 337 if (player_ctx->buffer->IsInDiscMenuOrStillFrame() || clear) 338 SetDVDBookmark(0); 339 else 340 SetDVDBookmark(framesPlayed); 345 if (!player_ctx->buffer->IsDVD()) 346 return; 347 348 QStringList fields; 349 QString name; 350 QString serialid; 351 QString dvdstate; 352 353 if (player_ctx->buffer->IsBookmarkAllowed() || clear) 354 { 355 if (!player_ctx->buffer->DVD()->GetNameAndSerialNum(name, serialid)) 356 { 357 LOG(VB_GENERAL, LOG_ERR, LOC + 358 "DVD has no name and serial number. Cannot set bookmark."); 359 return; 360 } 361 362 if (!clear && !player_ctx->buffer->DVD()->GetDVDStateSnapshot(dvdstate)) 363 { 364 LOG(VB_GENERAL, LOG_ERR, LOC + 365 "Unable to retrieve DVD state. Cannot set bookmark."); 366 return; 367 } 368 369 player_ctx->LockPlayingInfo(__FILE__, __LINE__); 370 if (player_ctx->playingInfo) 371 { 372 fields += serialid; 373 fields += name; 374 375 if (!clear) 376 { 377 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Set bookmark"); 378 fields += dvdstate; 379 } 380 else 381 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Clear bookmark"); 382 383 player_ctx->playingInfo->SaveDVDBookmark(fields); 384 385 } 386 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 387 } 341 388 } 342 389 343 390 uint64_t MythDVDPlayer::GetBookmark(void) … … uint64_t MythDVDPlayer::GetBookmark(void) 357 404 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__); 358 405 return 0; 359 406 } 407 360 408 dvdbookmark = player_ctx->playingInfo->QueryDVDBookmark(serialid); 409 361 410 if (!dvdbookmark.empty()) 362 411 { 363 412 QStringList::Iterator it = dvdbookmark.begin(); 364 m_initial_title = (*it).toInt(); 365 frames = (long long)((*++it).toLongLong() & 0xffffffffLL); 366 m_initial_audio_track = (*++it).toInt(); 367 m_initial_subtitle_track = (*++it).toInt(); 368 LOG(VB_PLAYBACK, LOG_INFO, LOC + 369 QString("Get Bookmark: title %1 audiotrack %2 subtrack %3 " 370 "frame %4") 371 .arg(m_initial_title).arg(m_initial_audio_track) 372 .arg(m_initial_subtitle_track).arg(frames)); 413 414 if (dvdbookmark.count() == 1) 415 { 416 m_initial_dvdstate = *it; 417 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Get Bookmark: bookmark found"); 418 } 419 else 420 { 421 // Legacy bookmarks 422 m_initial_title = (*it).toInt(); 423 frames = (long long)((*++it).toLongLong() & 0xffffffffLL); 424 m_initial_audio_track = (*++it).toInt(); 425 m_initial_subtitle_track = (*++it).toInt(); 426 LOG(VB_PLAYBACK, LOG_INFO, LOC + 427 QString("Get Bookmark: title %1 audiotrack %2 subtrack %3 " 428 "frame %4") 429 .arg(m_initial_title).arg(m_initial_audio_track) 430 .arg(m_initial_subtitle_track).arg(frames)); 431 } 373 432 } 374 433 } 375 434 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__); … … void MythDVDPlayer::GoToDVDProgram(bool direction) 592 651 player_ctx->buffer->DVD()->GoToNextProgram(); 593 652 } 594 653 595 void MythDVDPlayer::SetDVDBookmark(uint64_t frame)596 {597 if (!player_ctx->buffer->IsDVD())598 return;599 600 uint64_t framenum = frame;601 QStringList fields;602 QString name;603 QString serialid;604 int title = 0;605 int part;606 int audiotrack = -1;607 int subtitletrack = -1;608 if (!player_ctx->buffer->DVD()->GetNameAndSerialNum(name, serialid))609 {610 LOG(VB_GENERAL, LOG_ERR, LOC +611 "DVD has no name and serial number. Cannot set bookmark.");612 return;613 }614 615 if (!player_ctx->buffer->IsInDiscMenuOrStillFrame() &&616 player_ctx->buffer->DVD()->617 GetTotalTimeOfTitle() > 120 && frame > 0)618 {619 audiotrack = GetTrack(kTrackTypeAudio);620 if (GetCaptionMode() == kDisplayAVSubtitle)621 {622 subtitletrack = player_ctx->buffer->DVD()->GetTrack(623 kTrackTypeSubtitle);624 }625 player_ctx->buffer->DVD()->GetPartAndTitle(part, title);626 }627 else628 framenum = 0;629 630 player_ctx->LockPlayingInfo(__FILE__, __LINE__);631 if (player_ctx->playingInfo)632 {633 fields += serialid;634 fields += name;635 fields += QString("%1").arg(title);636 fields += QString("%1").arg(audiotrack);637 fields += QString("%1").arg(subtitletrack);638 fields += QString("%1").arg(framenum);639 player_ctx->playingInfo->SaveDVDBookmark(fields);640 LOG(VB_PLAYBACK, LOG_INFO, LOC +641 QString("Set Bookmark: title %1 audiotrack %2 subtrack %3 frame %4")642 .arg(title).arg(audiotrack).arg(subtitletrack).arg(framenum));643 }644 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);645 }646 647 654 int MythDVDPlayer::GetNumAngles(void) const 648 655 { 649 656 if (player_ctx->buffer->DVD() && player_ctx->buffer->DVD()->IsOpen()) -
mythtv/libs/libmythtv/DVD/mythdvdplayer.h
diff --git a/mythtv/libs/libmythtv/DVD/mythdvdplayer.h b/mythtv/libs/libmythtv/DVD/mythdvdplayer.h index f32620a..01be07f 100644
a b class MythDVDPlayer : public MythPlayer 63 63 virtual void AVSync(VideoFrame *buffer, bool limit_delay = false); 64 64 virtual void DisplayPauseFrame(void); 65 65 virtual void PreProcessNormalFrame(void); 66 virtual void VideoStart(void); 66 67 virtual bool VideoLoop(void); 67 68 virtual void EventStart(void); 68 69 virtual void EventEnd(void); … … class MythDVDPlayer : public MythPlayer 98 99 99 100 private: 100 101 void DoChangeDVDTrack(void); 101 void SetDVDBookmark(uint64_t frame);102 102 void DisplayDVDButton(void); 103 103 104 104 void DisplayLastFrame(void); … … class MythDVDPlayer : public MythPlayer 110 110 int m_initial_title; 111 111 int m_initial_audio_track; 112 112 int m_initial_subtitle_track; 113 QString m_initial_dvdstate; 113 114 114 115 // still frame timing 115 116 MythTimer m_stillFrameTimer; -
mythtv/libs/libmythtv/dbcheck.cpp
diff --git a/mythtv/libs/libmythtv/dbcheck.cpp b/mythtv/libs/libmythtv/dbcheck.cpp index 0bebaf8..8516790 100644
a b NULL 2401 2401 return false; 2402 2402 } 2403 2403 2404 if (dbver == "1312") 2405 { 2406 const char *updates[] = { 2407 // DVD bookmark updates 2408 "DELETE FROM `dvdbookmark` WHERE `framenum` = 0;", 2409 "ALTER TABLE dvdbookmark ADD COLUMN dvdstate varchar(1024) NOT NULL DEFAULT '';", 2410 NULL 2411 }; 2412 if (!performActualUpdate(&updates[0], "1313", dbver)) 2413 return false; 2414 } 2404 2415 return true; 2405 2416 } 2406 2417 -
mythtv/programs/mythfrontend/main.cpp
diff --git a/mythtv/programs/mythfrontend/main.cpp b/mythtv/programs/mythfrontend/main.cpp index 717978a..f596763 100644
a b static int internal_play_media(const QString &mrl, const QString &plot, 1118 1118 1119 1119 pginfo->SetProgramInfoType(pginfo->DiscoverProgramInfoType()); 1120 1120 1121 int64_t pos = 0;1121 bool bookmarkPresent = false; 1122 1122 1123 1123 if (pginfo->IsVideoDVD()) 1124 1124 { … … static int internal_play_media(const QString &mrl, const QString &plot, 1130 1130 if (dvd->GetNameAndSerialNum(name, serialid)) 1131 1131 { 1132 1132 QStringList fields = pginfo->QueryDVDBookmark(serialid); 1133 if (!fields.empty()) 1134 { 1135 QStringList::Iterator it = fields.begin(); 1136 pos = (int64_t)((*++it).toLongLong() & 0xffffffffLL); 1137 } 1133 bookmarkPresent = (fields.count() > 0); 1138 1134 } 1139 1135 } 1140 1136 else … … static int internal_play_media(const QString &mrl, const QString &plot, 1147 1143 delete dvd; 1148 1144 } 1149 1145 else if (pginfo->IsVideo()) 1150 pos = pginfo->QueryBookmark();1146 bookmarkPresent = (pginfo->QueryBookmark() > 0); 1151 1147 1152 if (useBookmark && pos > 0)1148 if (useBookmark && bookmarkPresent) 1153 1149 { 1154 1150 MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); 1155 1151 BookmarkDialog *bookmarkdialog = new BookmarkDialog(pginfo, mainStack);