Skip to content

Commit a0c45bd

Browse files
axxelmsmeissn
authored andcommitted
ptp: tune EOS_FocusInfoEx, FocusInfo event related code
With the re-enabled FocusInfoEx, the 5Ds spams the log and the --wait-event console output with a 64 entry long focus info list. Assuming no tooling is dependent on the particular string format of the FocusInfoEx value, since it seems to only ever contain a no-empty set of selected AF-points at the beginning of the capture process, where the event is 'swollowed' by the focus detection code. This changeset strips it down to only contain the list of selected AF-points, meaning without focus, we now get a simple "{}". Furthermore, the olcmask 0x0100 (FocusInfo) data of the 5Ds, R8 and R5m2 has been analyzed and the in-focus detection code during trigger_capture has been improved. See code comments for details.
1 parent ee446cb commit a0c45bd

File tree

2 files changed

+65
-63
lines changed

2 files changed

+65
-63
lines changed

camlibs/ptp2/library.c

Lines changed: 26 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5989,7 +5989,6 @@ camera_trigger_canon_eos_capture (Camera *camera, GPContext *context)
59895989
PTPCanonEOSEvent event;
59905990
int back_off_wait = 0;
59915991
uint32_t result;
5992-
struct timeval focus_start;
59935992
PTPDevicePropDesc dpd;
59945993

59955994
GP_LOG_D ("camera_trigger_canon_eos_capture");
@@ -6034,63 +6033,66 @@ camera_trigger_canon_eos_capture (Camera *camera, GPContext *context)
60346033
if (!is_canon_eos_m (params)) {
60356034
/* Regular EOS */
60366035
uint16_t res;
6037-
int manualfocus = 0, foundfocusinfo = 0;
6036+
int manual_focus = 0, in_focus = 0;
60386037

60396038
/* are we in manual focus mode ... value would be 3 */
60406039
if (PTP_RC_OK == ptp_canon_eos_getdevicepropdesc (params, PTP_DPC_CANON_EOS_FocusMode, &dpd)) {
60416040
if ((dpd.DataType == PTP_DTC_UINT32) && (dpd.CurrentValue.u32 == 3)) {
6042-
manualfocus = 1;
6041+
manual_focus = 1;
60436042
/* will do 1 pass through the focusing loop for good measure */
60446043
GP_LOG_D("detected manual focus. skipping focus detection logic");
60456044
}
60466045
}
60476046
ret = GP_OK;
6048-
/* half press now - initiate focusing and wait for result */
6047+
/* half press now - initiate focusing (second param = 1 -> disabled AF) and wait for result */
60496048
C_PTP_REP_MSG (ptp_canon_eos_remotereleaseon (params, 1, 0), _("Canon EOS Half-Press failed"));
60506049

6051-
focus_start = time_now();
6050+
/* at this point, the focusing is complete and either succeded or failed. This has been verified with
6051+
* a 5Dm2, 5Ds and R8. The RemoteReleaseOn call may take e.g. up to 8s on a 5Dm2 with a slow lens. */
6052+
struct timeval get_events_start = time_now();
60526053
do {
6053-
int foundevents = 0;
6054+
int received_events = 0;
60546055

60556056
C_PTP_REP_MSG (ptp_check_eos_events (params), _("Canon EOS Get Changes failed"));
60566057
while (ptp_get_one_eos_event (params, &event)) {
60576058
GP_LOG_D ("while focussing, processing event '%s'", ptp_get_eos_event_name(params, event.type));
6058-
foundevents = 1;
6059+
received_events = 1;
60596060
if (event.type == PTP_EOSEvent_FocusInfo) {
6060-
GP_LOG_D("focusinfo content: %s", event.u.info);
6061-
foundfocusinfo = 1;
6062-
if (strstr(event.u.info,"0000200")) {
6063-
gp_context_error (context, _("Canon EOS Capture failed to release: Perhaps no focus?"));
6061+
GP_LOG_D("FocusInfo content: %s", event.u.info);
6062+
if (strstr(event.u.info, "000000000101")) /* see OLCInfoChanged unpacking */
6063+
in_focus = 1;
6064+
else if (strstr(event.u.info, "000000000200") || strstr(event.u.info, "000000000000")) {
6065+
gp_context_error (context, _("Canon EOS Auto-Focus failed, could not capture."));
60646066
ret = GP_ERROR;
60656067
}
60666068
} else if ((event.type == PTP_EOSEvent_PropertyChanged) &&
60676069
(event.u.propid == PTP_DPC_CANON_EOS_FocusInfoEx)
60686070
) {
60696071
if (PTP_RC_OK == ptp_canon_eos_getdevicepropdesc (params, PTP_DPC_CANON_EOS_FocusInfoEx, &dpd)) {
6070-
GP_LOG_D("focusinfo prop content: %s", dpd.CurrentValue.str);
6071-
if (!strstr(dpd.CurrentValue.str,"select={}")) /* select={} means "no focus yet" */
6072-
foundfocusinfo = 1;
6072+
GP_LOG_D("EOS_FocusInfoEx prop content: %s", dpd.CurrentValue.str);
6073+
if (strcmp(dpd.CurrentValue.str, "{}")) /* "{}" means "no focus points found" */
6074+
in_focus = 1;
60736075
ptp_free_devicepropdesc (&dpd);
60746076
}
60756077
}
60766078
}
60776079
/* We found focus information, so half way pressing has finished! */
6078-
if (foundfocusinfo)
6080+
if (in_focus)
60796081
break;
60806082
/* for manual focus, wait until we received an event or 0.1s passed */
6081-
if (manualfocus && (foundevents || time_since (focus_start) >= 100))
6083+
if (manual_focus && (received_events || time_since (get_events_start) >= 100))
60826084
break;
6083-
} while (waiting_for_timeout (&back_off_wait, focus_start, 2*1000)); /* wait 2 seconds for focus */
6085+
} while (waiting_for_timeout (&back_off_wait, get_events_start, 500)); /* wait up to 500ms for focus events */
60846086

6085-
if (!foundfocusinfo && !manualfocus) {
6086-
GP_LOG_E("no focus info?\n");
6087+
if (!in_focus && !manual_focus) {
6088+
GP_LOG_E("Auto-Focus failed\n");
60876089
}
60886090
if (ret != GP_OK) {
60896091
C_PTP_REP_MSG (ptp_canon_eos_remotereleaseoff (params, 1), _("Canon EOS Half-Release failed"));
60906092
return ret;
60916093
}
6092-
/* full press now */
60936094

6095+
/* full press now */
60946096
res = LOG_ON_PTP_E (ptp_canon_eos_remotereleaseon (params, 2, 0));
60956097
if (res != PTP_RC_OK) {
60966098
/* if the Full Press failed, try to roll back the release and do not exit Half-Pressed. */
@@ -6113,7 +6115,8 @@ camera_trigger_canon_eos_capture (Camera *camera, GPContext *context)
61136115
int button = 0, eos_m_focus_done = 0;
61146116

61156117
C_PTP_REP_MSG (ptp_canon_eos_remotereleaseon (params, 3, 0), _("Canon EOS M Full-Press failed"));
6116-
focus_start = time_now();
6118+
6119+
struct timeval focus_start = time_now(); /* This might be a misnomer, see EOS case above. */
61176120
/* check if the capture was successful (the result is reported as a set of OLCInfoChanged events) */
61186121
do {
61196122
ptp_check_eos_events (params);
@@ -6775,9 +6778,9 @@ camera_wait_for_event (Camera *camera, int timeout,
67756778
PTPDevicePropDesc dpd;
67766779

67776780
*eventtype = GP_EVENT_UNKNOWN;
6778-
if (PTP_DPC_CANON_EOS_FocusInfoEx == event.u.propid) {
6781+
if (event.u.propid == PTP_DPC_CANON_EOS_FocusInfoEx) {
67796782
if (PTP_RC_OK == ptp_canon_eos_getdevicepropdesc (params, PTP_DPC_CANON_EOS_FocusInfoEx, &dpd)) {
6780-
*eventdata = aprintf("FocusInfo %s", dpd.CurrentValue.str);
6783+
*eventdata = aprintf("Focus Points %s", dpd.CurrentValue.str);
67816784
ptp_free_devicepropdesc (&dpd);
67826785
return GP_OK;
67836786
}

camlibs/ptp2/ptp-pack.c

Lines changed: 39 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1520,31 +1520,31 @@ ptp_pack_EOS_ImageFormat (PTPParams* params, unsigned char* data, uint16_t value
15201520
htod32a(data+=4, (value >> 0) & 0x7);
15211521
}
15221522

1523-
#undef PACK_5DM3_SMALL_JPEG_SIZE
1523+
#undef PACK_EOS_S123_JPEG_SIZE
15241524

15251525
return s;
15261526
}
15271527

1528-
/* 00: 32 bit size
1529-
* 04: 16 bit subsize
1530-
* 08: 16 bit version (?)
1531-
* 0c: 16 bit focus_points_in_struct
1532-
* 10: 16 bit focus_points_in_use
1533-
* 14: variable arrays:
1528+
/* 32 bit size
1529+
* 16 bit subsize
1530+
* 16 bit version (?)
1531+
* 16 bit focus_points_in_struct
1532+
* 16 bit focus_points_in_use
1533+
* variable arrays:
15341534
* 16 bit sizex, 16 bit sizey
15351535
* 16 bit othersizex, 16 bit othersizey
15361536
* 16 bit array height[focus_points_in_struct]
15371537
* 16 bit array width[focus_points_in_struct]
15381538
* 16 bit array offsetheight[focus_points_in_struct] middle is 0
15391539
* 16 bit array offsetwidth[focus_points_in_struct] middle is ?
15401540
* bitfield of selected focus points, starting with 0 [size focus_points_in_struct in bits]
1541-
* unknown stuff , likely which are active
1541+
* unknown stuff, likely which are active
15421542
* 16 bit 0xffff
15431543
*
15441544
* size=NxN,size2=NxN,points={NxNxNxN,NxNxNxN,...},selected={0,1,2}
15451545
*/
15461546
static inline char*
1547-
ptp_unpack_EOS_FocusInfoEx (PTPParams* params, const unsigned char** data, uint32_t datasize )
1547+
ptp_unpack_EOS_FocusInfoEx (PTPParams* params, const unsigned char** data, uint32_t datasize)
15481548
{
15491549
uint32_t size = dtoh32a( *data );
15501550
uint32_t halfsize = dtoh16a( (*data) + 4);
@@ -1569,11 +1569,6 @@ ptp_unpack_EOS_FocusInfoEx (PTPParams* params, const unsigned char** data, uint3
15691569
ptp_debug(params, "skipped FocusInfoEx data (zero filled)");
15701570
return strdup("no focus points returned by camera");
15711571
}
1572-
1573-
/* every focuspoint gets 4 (16 bit number possible "-" sign and a x) and a ,*/
1574-
/* initial things around lets say 100 chars at most.
1575-
* FIXME: check selected when we decode it
1576-
*/
15771572
if (size < focus_points_in_struct*8) {
15781573
ptp_error(params, "focus_points_in_struct %d is too large vs size %d", focus_points_in_struct, size);
15791574
return strdup("bad size 2");
@@ -1582,54 +1577,48 @@ ptp_unpack_EOS_FocusInfoEx (PTPParams* params, const unsigned char** data, uint3
15821577
ptp_error(params, "focus_points_in_use %d is larger than focus_points_in_struct %d", focus_points_in_use, focus_points_in_struct);
15831578
return strdup("bad size 3");
15841579
}
1585-
1586-
maxlen = focus_points_in_use*32 + 100 + (size - focus_points_in_struct*8)*2;
15871580
if (halfsize != size-4) {
1588-
ptp_error(params, "halfsize %d is not expected %d", halfsize, size-4);
1589-
return strdup("bad size 4");
1581+
ptp_debug(params, "halfsize %d is not expected %d", halfsize, size-4);
15901582
}
1583+
15911584
if (20 + focus_points_in_struct*8 + (focus_points_in_struct+7)/8 > size) {
15921585
ptp_error(params, "size %d is too large for fp in struct %d", focus_points_in_struct*8 + 20 + (focus_points_in_struct+7)/8, size);
15931586
return strdup("bad size 5");
15941587
}
1588+
1589+
ptp_debug(params," prop d1d3 version is %d with %d focus points in struct and %d in use, size=%ux%u, size2=%ux%u",
1590+
version, focus_points_in_struct, focus_points_in_use, sizeX, sizeY, size2X, size2Y);
15951591
#if 0
1596-
ptp_debug(params,"d1d3 content:");
1597-
for (i=0;i<size;i+=2)
1598-
ptp_debug(params,"%d: %02x %02x", i, (*data)[i], (*data)[i+1]);
1592+
ptp_debug_data(params, *data, datasize);
15991593
#endif
1600-
ptp_debug(params," version of d1d3 is %d with %d focus points in struct and %d in use",
1601-
version, focus_points_in_struct, focus_points_in_use);
16021594

1595+
/* every selected focus_point gets an entry like "{N,N,N,N}," where N can be 5 chars long */
1596+
maxlen = 1 + focus_points_in_use * 26 + 2;
16031597
str = (char*)malloc( maxlen );
16041598
if (!str)
16051599
return NULL;
16061600
p = str;
16071601

1608-
p += sprintf(p,"eosversion=%u,size=%ux%u,size2=%ux%u,points={", version, sizeX, sizeY, size2X, size2Y);
1602+
/* output only the selected AF-points, so no AF means you get an empty list: "{}" */
1603+
p += sprintf(p,"{");
16091604
for (i=0;i<focus_points_in_use;i++) {
1605+
if (((1<<(i%8)) & (*data)[focus_points_in_struct*8+20+i/8]) == 0)
1606+
continue;
16101607
int16_t x = dtoh16a((*data) + focus_points_in_struct*4 + 20 + 2*i);
16111608
int16_t y = dtoh16a((*data) + focus_points_in_struct*6 + 20 + 2*i);
16121609
int16_t w = dtoh16a((*data) + focus_points_in_struct*2 + 20 + 2*i);
16131610
int16_t h = dtoh16a((*data) + focus_points_in_struct*0 + 20 + 2*i);
16141611

1615-
p += sprintf(p,"{%d,%d,%d,%d}",x,y,w,h);
1616-
1617-
if (i<focus_points_in_use-1)
1618-
p += sprintf(p,",");
1619-
}
1620-
p += sprintf(p,"},select={");
1621-
for (i=0;i<focus_points_in_use;i++) {
1622-
if ((1<<(i%8)) & ((*data)[focus_points_in_struct*8+20+i/8]))
1623-
p+=sprintf(p,"%u,", i);
1624-
}
1625-
1626-
p += sprintf(p,"},unknown={");
1627-
for (i=focus_points_in_struct*8+(focus_points_in_struct+7)/8+20;i<size;i++) {
1628-
if ((p-str) > maxlen - 4)
1612+
int n = snprintf(p, maxlen - (p - str), "{%d,%d,%d,%d},", x, y, w, h);
1613+
if (n < 0 || n > maxlen - (p - str)) {
1614+
ptp_error(params, "snprintf buffer overflow in %s", __func__);
16291615
break;
1630-
p+=sprintf(p,"%02x", (*data)[i]);
1616+
}
1617+
p += n;
16311618
}
1632-
p += sprintf(p,"}");
1619+
if (p[-1] == ',')
1620+
p--;
1621+
p += sprintf(p, "}");
16331622
return str;
16341623
}
16351624

@@ -2408,6 +2397,16 @@ static unsigned int olcsizes[0x15][13] = {
24082397
case 0x0100: /* Focus Info */
24092398
/* mask 0x0100: 6 bytes, 00 00 00 00 00 00 (before focus) and
24102399
* 00 00 00 00 01 00 (on focus) observed */
2400+
/* a full trigger capture cycle on the 5Ds with enabled and acting auto-focus looks like this
2401+
0.098949 6 bytes: 00 00 00 00 00 00 (first GetEvent)
2402+
0.705762 6 bytes: 00 00 00 00 00 01 (first GetEvent after half-press-on, together with FocusInfoEx == {})
2403+
0.758275 6 bytes: 00 00 00 00 01 01 (second GetEvent after half-press-on, together with FocusInfoEx == {...})
2404+
0.962160 6 bytes: 00 00 00 00 01 00 (couple GetEvents later, together with 3x FocusInfoEx == {} and next line)
2405+
0.962300 6 bytes: 00 00 00 00 00 00
2406+
On AF-failure, the 5Ds sequence is 0-1, 2-2, 2-0, 0-0.
2407+
The R8 looks similar except another 00 byte is appended and on sucess it jumps directly from 1-1 to 0-0.
2408+
On an AF-failure, it jumps from 0-1 to 0-0. The R5m2 has seen to fail with 0-1, 2-1, 2-0, 0-0.
2409+
*/
24112410
e[i].type = PTP_EOSEvent_FocusInfo;
24122411
PTP_CANON_SET_INFO(e[i], "%s", ptp_bytes2str(curdata + curoff, olcsizes[olcver][j], "%02x"));
24132412
break;

0 commit comments

Comments
 (0)