forked from chrischdi/gphoto2go
-
Notifications
You must be signed in to change notification settings - Fork 1
/
camerafilereader.go
82 lines (66 loc) · 1.5 KB
/
camerafilereader.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package gphoto2go
// #cgo pkg-config: libgphoto2
// #include <gphoto2.h>
// #include <stdlib.h>
import "C"
import (
"io"
"reflect"
"unsafe"
)
// Need to find a good buffer size
// For now, let's try 1MB
const fileReaderBufferSize = 20 * 1024 * 1024
type cameraFileReader struct {
camera *Camera
folder string
fileName string
fullSize uint64
offset uint64
closed bool
cCameraFile *C.CameraFile
cBuffer *C.char
buffer [fileReaderBufferSize]byte
}
func (cfr *cameraFileReader) Read(p []byte) (int, error) {
if cfr.closed {
return 0, io.ErrClosedPipe
}
n := uint64(len(p))
if n == 0 {
return 0, nil
}
bufLen := uint64(len(cfr.buffer))
remaining := cfr.fullSize - cfr.offset
toRead := bufLen
if toRead > remaining {
toRead = remaining
}
if toRead > n {
toRead = n
}
// From: https://code.google.com/p/go-wiki/wiki/cgo
// Turning C arrays into Go slices
sliceHeader := reflect.SliceHeader{
Data: uintptr(unsafe.Pointer(cfr.cBuffer)),
Len: int(cfr.fullSize),
Cap: int(cfr.fullSize),
}
goSlice := *(*[]C.char)(unsafe.Pointer(&sliceHeader))
for i := uint64(0); i < toRead; i++ {
p[i] = byte(goSlice[cfr.offset+i])
}
cfr.offset += toRead
if cfr.offset < cfr.fullSize {
return int(toRead), nil
}
return int(toRead), io.EOF
}
func (cfr *cameraFileReader) Close() error {
if !cfr.closed {
// If I understand correctly, freeing the CameraFile will also free the data buffer (ie. cfr.cBuffer)
C.gp_file_free(cfr.cCameraFile)
cfr.closed = true
}
return nil
}