Changeset 720
- Timestamp:
- 03/14/09 22:43:07 (4 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
-
core/curves.c (modified) (2 diffs)
-
core/luascript.c (modified) (3 diffs)
-
core/raw.c (modified) (6 diffs)
-
core/raw_merge.c (modified) (9 diffs)
-
core/shot_histogram.c (modified) (4 diffs)
-
include/camera.h (modified) (4 diffs)
-
platform/g9/sub/100d/stubs_entry.S (modified) (2 diffs)
-
platform/g9/sub/100g/stubs_entry.S (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/core/curves.c
r709 r720 3 3 #include "stdlib.h" 4 4 #include "raw.h" 5 6 #ifdef OPT_CURVES 7 5 8 #include "curves.h" 6 9 … … 390 393 } 391 394 395 #endif -
trunk/core/luascript.c
r711 r720 13 13 #include "raw.h" 14 14 #include "raw_merge.h" 15 16 #ifdef OPT_CURVES 15 17 #include "curves.h" 16 18 … … 22 24 return 0; 23 25 } 24 26 #endif 25 27 26 28 static int luaCB_set_aflock(lua_State* L) … … 1016 1018 FUNC(set_backlight); 1017 1019 FUNC(set_aflock); 1020 #ifdef OPT_CURVES 1018 1021 FUNC(set_curve_state); 1019 } 1022 #endif 1023 } -
trunk/core/raw.c
r694 r720 39 39 char* get_raw_image_addr(void){ 40 40 if (!conf.raw_cache) return hook_raw_image_addr(); 41 else return (char*) ((int)hook_raw_image_addr()&~ 0x10000000);41 else return (char*) ((int)hook_raw_image_addr()&~CAM_UNCACHED_BIT); 42 42 } 43 43 … … 78 78 y=CAM_ACTIVE_AREA_Y1+((CAM_ACTIVE_AREA_Y2-CAM_ACTIVE_AREA_Y1)*i)/DNG_TH_HEIGHT; 79 79 #if cam_CFAPattern==0x02010100 // Red Green Green Blue 80 r=gamma[get_raw_pixel((x/2)*2,(y/2)*2)>> 2]; // red pixel81 g=gamma[6*(get_raw_pixel((x/2)*2+1,(y/2)*2)>> 2)/10]; // green pixel82 b=gamma[get_raw_pixel((x/2)*2+1,(y/2)*2+1)>> 2]; //blue pixel80 r=gamma[get_raw_pixel((x/2)*2,(y/2)*2)>>(CAM_SENSOR_BITS_PER_PIXEL-8)]; // red pixel 81 g=gamma[6*(get_raw_pixel((x/2)*2+1,(y/2)*2)>>(CAM_SENSOR_BITS_PER_PIXEL-8))/10]; // green pixel 82 b=gamma[get_raw_pixel((x/2)*2+1,(y/2)*2+1)>>(CAM_SENSOR_BITS_PER_PIXEL-8)]; //blue pixel 83 83 #elif cam_CFAPattern==0x01000201 // Green Blue Red Green 84 r=gamma[get_raw_pixel((x/2)*2,(y/2)*2+1)>> 2]; // red pixel85 g=gamma[6*(get_raw_pixel((x/2)*2,(y/2)*2)>> 2)/10]; // green pixel86 b=gamma[get_raw_pixel((x/2)*2+1,(y/2)*2)>> 2]; //blue pixel84 r=gamma[get_raw_pixel((x/2)*2,(y/2)*2+1)>>(CAM_SENSOR_BITS_PER_PIXEL-8)]; // red pixel 85 g=gamma[6*(get_raw_pixel((x/2)*2,(y/2)*2)>>(CAM_SENSOR_BITS_PER_PIXEL-8))/10]; // green pixel 86 b=gamma[get_raw_pixel((x/2)*2+1,(y/2)*2)>>(CAM_SENSOR_BITS_PER_PIXEL-8)]; //blue pixel 87 87 #else 88 88 #error please define new pattern here … … 219 219 220 220 void set_raw_pixel(unsigned int x, unsigned int y, unsigned short value){ 221 #if CAM_SENSOR_BITS_PER_PIXEL==10 221 222 unsigned char* addr=(unsigned char*)get_raw_image_addr()+y*RAW_ROWLEN+(x/8)*CAM_SENSOR_BITS_PER_PIXEL; 222 #if CAM_SENSOR_BITS_PER_PIXEL==10223 223 switch (x%8) { 224 224 case 0: addr[0]=(addr[0]&0x3F)|(value<<6); addr[1]=value>>2; break; … … 231 231 case 7: addr[8]=value; addr[9]=(addr[9]&0xFC)|(value>>8); break; 232 232 } 233 #elif CAM_SENSOR_BITS_PER_PIXEL==12 234 unsigned char* addr=(unsigned char*)get_raw_image_addr()+y*RAW_ROWLEN+(x/4)*6; 235 switch (x%4) { 236 case 0: addr[0] = (addr[0]&0x0F) | (unsigned char)(value << 4); addr[1] = (unsigned char)(value >> 4); break; 237 case 1: addr[0] = (addr[0]&0xF0) | (unsigned char)(value >> 8); addr[3] = (unsigned char)value; break; 238 case 2: addr[2] = (unsigned char)(value >> 4); addr[5] = (addr[5]&0x0F) | (unsigned char)(value << 4); break; 239 case 3: addr[4] = (unsigned char)value; addr[5] = (addr[5]&0xF0) | (unsigned char)(value >> 8); break; 240 } 233 241 #else 234 242 #error define set_raw_pixel for sensor bit depth … … 238 246 //------------------------------------------------------------------- 239 247 unsigned short get_raw_pixel(unsigned int x,unsigned int y){ 248 #if CAM_SENSOR_BITS_PER_PIXEL==10 240 249 unsigned char* addr=(unsigned char*)get_raw_image_addr()+y*RAW_ROWLEN+(x/8)*CAM_SENSOR_BITS_PER_PIXEL; 241 #if CAM_SENSOR_BITS_PER_PIXEL==10242 250 switch (x%8) { 243 251 case 0: return ((0x3fc&(((unsigned short)addr[1])<<2)) | (addr[0] >> 6)); … … 249 257 case 6: return ((0x3c0&(((unsigned short)addr[6])<<6)) | (addr[9] >> 2)); 250 258 case 7: return ((0x300&(((unsigned short)addr[9])<<8)) | (addr[8])); 259 } 260 #elif CAM_SENSOR_BITS_PER_PIXEL==12 261 unsigned char* addr=(unsigned char*)get_raw_image_addr()+y*RAW_ROWLEN+(x/4)*6; 262 switch (x%4) { 263 case 0: return ((unsigned short)(addr[1]) << 4) | (addr[0] >> 4); 264 case 1: return ((unsigned short)(addr[0] & 0x0F) << 8) | (addr[3]); 265 case 2: return ((unsigned short)(addr[2]) << 4) | (addr[5] >> 4); 266 case 3: return ((unsigned short)(addr[5] & 0x0F) << 8) | (addr[4]); 251 267 } 252 268 #else -
trunk/core/raw_merge.c
r594 r720 21 21 // this may or may not be what you want 22 22 static int raw_subtract_values(int from, int sub) { 23 if ( sub > conf.sub_in_dark_value ) {23 /* if ( sub > conf.sub_in_dark_value ) { 24 24 int result = from - sub; 25 25 if ( result < conf.sub_out_dark_value ) { … … 32 32 else { 33 33 return from; 34 } 34 }*/ 35 36 int result; 37 if ((from==0) || (sub==0)) return 0; // bad pixel 38 result = from - sub + CAM_BLACK_LEVEL; 39 if (result<CAM_BLACK_LEVEL) result=CAM_BLACK_LEVEL; 40 if (result>CAM_WHITE_LEVEL) result=CAM_WHITE_LEVEL; 41 return result; 42 35 43 } 36 44 /* subtract "sub" from "from" and store the result in "dest"*/ 37 45 /* TODO allow replacing if dest == from or sub*/ 38 46 int raw_subtract(const char *from, const char *sub, const char *dest) { 39 unsigned req=(hook_raw_size()>>10) + 1;47 unsigned req=(hook_raw_size()>>10) + 1; 40 48 unsigned avail=GetFreeCardSpaceKb(); 41 49 FILE *ffrom = NULL, *fsub = NULL, *fdest = NULL; … … 66 74 fread(baccum,1, RAW_ROWLEN,ffrom); 67 75 fread(bsub,1, RAW_ROWLEN,fsub); 76 77 #if CAM_SENSOR_BITS_PER_PIXEL==10 78 68 79 for(i = 0;i<RAW_ROWLEN; i+=10) { 69 80 s =((0x3fc&(((unsigned short)bsub[i+1])<<2)) | (bsub[i+0] >> 6)); … … 118 129 baccum[i+9]=(baccum[i+9]&0xFC)|(d>>8); 119 130 } 131 132 #elif CAM_SENSOR_BITS_PER_PIXEL==12 133 134 for(i = 0;i<RAW_ROWLEN; i+=6) { 135 136 s=((0xFF0&(((unsigned short)bsub[i+1])<<4)) | (bsub[i+0] >> 4)); 137 d=((0xFF0&(((unsigned short)baccum[i+1])<<4)) | (baccum[i+0] >> 4)); 138 d = raw_subtract_values(d,s); 139 baccum[i+0]=(baccum[i+0]&0x0F)|(d<<4); 140 baccum[i+1]=d>>4; 141 142 s=((0xF00&(((unsigned short)bsub[i+0])<<8)) | (bsub[i+3] )); 143 d=((0xF00&(((unsigned short)baccum[i+0])<<8)) | (baccum[i+3] )); 144 d = raw_subtract_values(d,s); 145 baccum[i+0]=(baccum[i+0]&0xF0)|(d>>8); 146 baccum[i+3]=d; 147 148 s=((0xFF0&(((unsigned short)bsub[i+2])<<4)) | (bsub[i+5] >> 4)); 149 d=((0xFF0&(((unsigned short)baccum[i+2])<<4)) | (baccum[i+5] >> 4)); 150 d = raw_subtract_values(d,s); 151 baccum[i+2]=d>>4; 152 baccum[i+5]=(baccum[i+5]&0x0F)|(d<<4); 153 154 s=((0xF00&(((unsigned short)bsub[i+5])<<8)) | (bsub[i+4] )); 155 d=((0xF00&(((unsigned short)baccum[i+5])<<8)) | (baccum[i+4] )); 156 d = raw_subtract_values(d,s); 157 baccum[i+4]=d; 158 baccum[i+5]=(baccum[i+5]&0xF0)|(d>>8); 159 } 160 161 #else 162 #error define set_raw_pixel for sensor bit depth 163 #endif 164 120 165 fwrite(baccum,1,RAW_ROWLEN,fdest); 121 166 if ( (j & 0x1F) == 0 ) { … … 192 237 193 238 for (nrow=0,j=0;nrow<CAM_RAW_ROWS;nrow++,j++){ 239 240 #if CAM_SENSOR_BITS_PER_PIXEL==10 241 194 242 for (i=0,src=0; i<CAM_RAW_ROWPIX; i+=8, src+=10){ 195 243 row[i+0]+=((0x3fc&(((unsigned short)rawrow[src+1])<<2)) | (rawrow[src+0] >> 6)); … … 202 250 row[i+7]+=((0x300&(((unsigned short)rawrow[src+9])<<8)) | (rawrow[src+8])); 203 251 } 252 253 #elif CAM_SENSOR_BITS_PER_PIXEL==12 254 255 for (i=0,src=0; i<CAM_RAW_ROWPIX; i+=4, src+=6){ 256 row[i+0]+=((0xFF0&(((unsigned short)rawrow[src+1])<<4)) | (rawrow[src+0] >> 4)); 257 row[i+1]+=((0xF00&(((unsigned short)rawrow[src+0])<<8)) | (rawrow[src+3] )); 258 row[i+2]+=((0xFF0&(((unsigned short)rawrow[src+2])<<4)) | (rawrow[src+5] >> 4)); 259 row[i+3]+=((0xF00&(((unsigned short)rawrow[src+5])<<8)) | (rawrow[src+4] )); 260 } 261 262 #else 263 #error define set_raw_pixel for sensor bit depth 264 #endif 265 204 266 fwrite(row, 1, CAM_RAW_ROWPIX*sizeof(unsigned short), fbrawout); 205 267 if (raw_count) … … 232 294 FILE *fbraw, *fcraw; 233 295 static struct utimbuf t; 234 #define BLACK_LEVEL 32235 296 if (!raw_count) 236 297 return; … … 253 314 row[i]/=raw_count; 254 315 else { 255 if (row[i]> BLACK_LEVEL*(raw_count-1))256 row[i]-= BLACK_LEVEL*(raw_count-1);316 if (row[i]>CAM_BLACK_LEVEL*(raw_count-1)) 317 row[i]-=CAM_BLACK_LEVEL*(raw_count-1); 257 318 else 258 319 row[i]=0; 259 if (row[i]> 0x3FF)260 row[i]= 0x3FF;320 if (row[i]>CAM_WHITE_LEVEL) 321 row[i]=CAM_WHITE_LEVEL; 261 322 } 262 323 } 263 324 #if CAM_SENSOR_BITS_PER_PIXEL==10 264 325 for (i=0,src=0;i<CAM_RAW_ROWPIX;i+=8,src+=10) { 265 326 rawrow[src+0]=(row[i+0]<<6)|(row[i+1]>>4); … … 274 335 rawrow[src+9]=(row[i+6]<<2)|(row[i+7]>>8); 275 336 } 337 #elif CAM_SENSOR_BITS_PER_PIXEL==12 338 for (i=0,src=0; i<CAM_RAW_ROWPIX; i+=4, src+=6){ 339 rawrow[src+0]=(row[i+0]<<4)|(row[i+1]>>8); 340 rawrow[src+1]=(row[i+0]>>4); 341 rawrow[src+2]=(row[i+2]>>4); 342 rawrow[src+3]= row[i+1]; 343 rawrow[src+4]= row[i+3]; 344 rawrow[src+5]=(row[i+2]<<4)|(row[i+3]>>8); 345 } 346 #else 347 #error define set_raw_pixel for sensor bit depth 348 #endif 349 276 350 fwrite(rawrow, 1, RAW_ROWLEN, fcraw); 277 351 fread(row, 1, CAM_RAW_ROWPIX*sizeof(unsigned short), fbraw); -
trunk/core/shot_histogram.c
r687 r720 9 9 #define RAW_TARGET_FILENAME "%s_%04d.%s" 10 10 11 // we could use sensor bitdepth here. For now, we just discard low bits if > 10bpp 11 12 #define SHOT_HISTOGRAM_SAMPLES 1024 12 13 #define SHOT_HISTOGRAM_SIZE (SHOT_HISTOGRAM_SAMPLES*sizeof(short)) … … 39 40 void build_shot_histogram() 40 41 { 41 // read samples from RAW memory and build an histogram of its luminosity42 // read samples from RAW memory and build an histogram of its luminosity 42 43 // actually, it' just reading pixels, ignoring difference between R, G and B, 43 44 // we just need an estimate of luminance … … 73 74 { 74 75 p=get_raw_pixel(x,y); 76 // > 10bpp compatibility: discard the lowest N bits 77 #if CAM_SENSOR_BITS_PER_PIXEL > 10 78 p >>= CAM_SENSOR_BITS_PER_PIXEL-10; 79 #endif 75 80 shot_histogram[p]++; 76 81 } … … 105 110 if(!shot_histogram_isenabled()) // TODO we could return an error somehow 106 111 return 0; 107 for (x = 0 ; x < 1024; x ++ )112 for (x = 0 ; x < SHOT_HISTOGRAM_SAMPLES; x ++ ) 108 113 { 109 114 tot += shot_histogram[x]; -
trunk/include/camera.h
r718 r720 53 53 #undef CAM_BRACKETING // Cameras that have bracketing (focus & ev) in original firmware already, most likely s- & g-series (propcase for digic III not found yet!) 54 54 55 #define CAM_UNCACHED_BIT 0x10000000 // bit indicating the uncached memory 56 55 57 #define CAM_MAKE "Canon" 56 #define CAM_SENSOR_BITS_PER_PIXEL 10 // Bits per pixel. Only value of 10 is currently supported58 #define CAM_SENSOR_BITS_PER_PIXEL 10 // Bits per pixel. 10 is standard, 12 is supported except for curves 57 59 #define CAM_WHITE_LEVEL ((1<<CAM_SENSOR_BITS_PER_PIXEL)-1) 58 60 #define CAM_BLACK_LEVEL 31 … … 1348 1350 #define DNG_EXT_FROM ".CR2" 1349 1351 1352 #elif defined (CAMERA_ixus980_sd990) 1353 #define CAM_PROPSET 2 // all values checked so far match propset 2 1354 #define CAM_DRYOS 1 1355 1356 #define CAM_RAW_ROWPIX 4480 // 14.7 MP 12bpp 1357 #define CAM_RAW_ROWS 3348 1358 1359 #undef CAM_USE_ZOOM_FOR_MF 1360 #undef CAM_HAS_ERASE_BUTTON 1361 #undef CAM_HAS_IRIS_DIAPHRAGM 1362 #define CAM_HAS_ND_FILTER 1 1363 #define CAM_HAS_MANUAL_FOCUS 1 1364 #define CAM_HAS_USER_TV_MODES 1 //include M/P ? needed to make Tv bracketing work 1365 #define CAM_SHOW_OSD_IN_SHOOT_MENU 1 1366 #undef CAM_CHDK_HAS_EXT_VIDEO_MENU 1367 #define CAM_NEED_SCREENLOCK 1 1368 #define CAM_NEED_VIEWPORT_WIDTH 1 1369 #undef CAM_UNCACHED_BIT // shut up compiler 1370 #define CAM_UNCACHED_BIT 0x40000000 1371 #undef CAM_BITMAP_PALETTE 1372 #define CAM_BITMAP_PALETTE 2 1373 1374 #undef CAM_BLACK_LEVEL 1375 #define CAM_BLACK_LEVEL 127 1376 // #define CAM_HAS_JOGDIAL 1 1377 // #define CAM_AF_SCAN_DURING_VIDEO_RECORD 1 1378 // #define CAM_CAN_UNLOCK_OPTICAL_ZOOM_IN_VIDEO 1 1379 // disabled until we get movie task running 1380 #undef CAM_CAN_UNLOCK_OPTICAL_ZOOM_IN_VIDEO 1381 // #define CAM_REMOTE 1 1382 // #define CAM_SYNCH 1 1383 #undef CAM_SENSOR_BITS_PER_PIXEL 1384 #define CAM_SENSOR_BITS_PER_PIXEL 12 1385 #undef CAM_WHITE_LEVEL 1386 #define CAM_WHITE_LEVEL ((1<<CAM_SENSOR_BITS_PER_PIXEL)-1) 1387 1388 #define DNG_SUPPORT 1 1389 // pattern 1390 // #define cam_CFAPattern 0x02010100 // Red Green Green Blue 1391 #define cam_CFAPattern 0x01000201 // Green Blue Red Green 1392 // color TODO 1393 #define CAM_COLORMATRIX1 \ 1394 837237, 1000000, -290137, 1000000, -128156, 1000000, \ 1395 -127762, 1000000, 643909, 1000000, 52973, 1000000, \ 1396 4446, 1000000, 88354, 1000000, 224246, 1000000 1397 1398 #define cam_CalibrationIlluminant1 1 // Daylight 1399 // cropping 1400 // TODO, capture the full frame for now 1401 #define CAM_JPEG_WIDTH 4416 1402 #define CAM_JPEG_HEIGHT 3312 1403 #define CAM_ACTIVE_AREA_X1 12 1404 #define CAM_ACTIVE_AREA_Y1 12 1405 #define CAM_ACTIVE_AREA_X2 4444 1406 #define CAM_ACTIVE_AREA_Y2 3324 1407 // camera name 1408 #define PARAM_CAMERA_NAME 4 // parameter number for GetParameterData sd990: OK 1409 1410 // #define DNG_EXT_FROM ".CR2" 1411 1350 1412 //========================================================== 1351 1413 // S-Series … … 1537 1599 //---------------------------------------------------------- 1538 1600 1601 #elif defined (CAMERA_sx10) 1602 #define CAM_PROPSET 2 1603 #define CAM_DRYOS 1 1604 1605 #define CAM_RAW_ROWPIX 3720 1606 #define CAM_RAW_ROWS 2772 1607 1608 #define CAM_SWIVEL_SCREEN 1 1609 #define CAM_ADJUSTABLE_ALT_BUTTON 1 1610 #undef CAM_CAN_SD_OVER_NOT_IN_MF 1611 #undef CAM_CAN_UNLOCK_OPTICAL_ZOOM_IN_VIDEO 1612 #define CAM_HAS_VIDEO_BUTTON 1 1613 #undef CAM_CHDK_HAS_EXT_VIDEO_MENU 1614 #define CAM_BRACKETING 1 1615 #undef CAM_VIDEO_CONTROL 1616 #define CAM_MULTIPART 1 1617 #define CAM_HAS_JOGDIAL 1 1618 #undef CAM_USE_ZOOM_FOR_MF 1619 #undef CAM_UNCACHED_BIT // shut up compiler 1620 #define CAM_UNCACHED_BIT 0x40000000 1621 1622 // #undef OPT_CURVES 1623 1624 #define DNG_SUPPORT 1 1625 // pattern 1626 #define cam_CFAPattern 0x02010100 // Red Green Green Blue 1627 // color 1628 #define CAM_COLORMATRIX1 \ 1629 650591, 1000000, -199585, 1000000, -123118, 1000000, \ 1630 -69617, 1000000, 583926, 1000000, 34354, 1000000, \ 1631 -19113, 1000000, 82163, 1000000, 210786, 1000000 1632 1633 #define cam_CalibrationIlluminant1 1 // Daylight 1634 // cropping 1635 #define CAM_JPEG_WIDTH 3648 1636 #define CAM_JPEG_HEIGHT 2736 1637 #define CAM_ACTIVE_AREA_X1 6 1638 #define CAM_ACTIVE_AREA_Y1 12 1639 #define CAM_ACTIVE_AREA_X2 3690 1640 #define CAM_ACTIVE_AREA_Y2 2772 1641 // camera name 1642 #define PARAM_CAMERA_NAME 4 // parameter number for GetParameterData 1643 #undef CAM_SENSOR_BITS_PER_PIXEL 1644 #undef CAM_WHITE_LEVEL 1645 #undef CAM_BLACK_LEVEL 1646 #define CAM_SENSOR_BITS_PER_PIXEL 12 1647 #define CAM_WHITE_LEVEL ((1<<CAM_SENSOR_BITS_PER_PIXEL)-1) 1648 #define CAM_BLACK_LEVEL 127 1649 1650 //---------------------------------------------------------- 1651 1539 1652 #else 1540 1653 #error camera type not defined … … 1542 1655 #endif 1543 1656 1657 // curves only work in 10bpp for now 1658 #if CAM_SENSOR_BITS_PER_PIXEL != 10 1659 #undef OPT_CURVES 1660 #endif 1661 1544 1662 #endif /* CAMERA_H */ -
trunk/platform/g9/sub/100d/stubs_entry.S
r679 r720 68 68 NSTUB(SleepTask, 0xff82a610) 69 69 NSTUB(TakeSemaphore, 0xff81b98c) 70 // Best match: 58% 71 NSTUB(TurnOffBackLight, 0xff87ff88) 72 // Best match: 77% 73 NSTUB(TurnOnBackLight, 0xff87ff70) 70 74 NSTUB(UIFS_WriteFirmInfoToFile, 0xff99c320) 71 75 NSTUB(UnlockMainPower, 0xff873144) … … 125 129 NSTUB(vsprintf, 0xff81e6f8) 126 130 NSTUB(write, 0xff81a3d8) 127 NSTUB(TurnOffBackLight, 0xff87ff88)128 NSTUB(TurnOnBackLight, 0xff87ff70) -
trunk/platform/g9/sub/100g/stubs_entry.S
r679 r720 68 68 NSTUB(SleepTask, 0xff82a610) 69 69 NSTUB(TakeSemaphore, 0xff81b98c) 70 // Best match: 58% 71 NSTUB(TurnOffBackLight, 0xff87ff88) 72 // Best match: 77% 73 NSTUB(TurnOnBackLight, 0xff87ff70) 70 74 NSTUB(UIFS_WriteFirmInfoToFile, 0xff99c390) 71 75 NSTUB(UnlockMainPower, 0xff873144) … … 125 129 NSTUB(vsprintf, 0xff81e6f8) 126 130 NSTUB(write, 0xff81a3d8) 127 NSTUB(TurnOffBackLight, 0xff88ff88)128 NSTUB(TurnOnBackLight, 0xff88ff70)
Note: See TracChangeset
for help on using the changeset viewer.