@@ -33,26 +33,54 @@ AVIOFileLikeContext::AVIOFileLikeContext(
3333 py::hasattr (fileLike, " seek" ),
3434 " File like object must implement a seek method." );
3535 }
36- createAVIOContext (&read, &write, &seek, &fileLike_, isForWriting);
36+ createAVIOContext (
37+ &readCallback, &writeCallback, &seekCallback, this , isForWriting);
3738}
3839
39- int AVIOFileLikeContext::read (void * opaque, uint8_t * buf, int buf_size) {
40- auto fileLike = static_cast <UniquePyObject*>(opaque);
40+ int AVIOFileLikeContext::readCallback (
41+ void * opaque,
42+ uint8_t * buf,
43+ int buf_size) {
44+ auto self = static_cast <AVIOFileLikeContext*>(opaque);
45+ int result = self->read (buf, buf_size);
46+ return result < 0 ? AVERROR_EOF : result;
47+ }
4148
42- // Note that we acquire the GIL outside of the loop. This is likely more
43- // efficient than releasing and acquiring it each loop iteration.
49+ int64_t
50+ AVIOFileLikeContext::seekCallback (void * opaque, int64_t offset, int whence) {
51+ if (whence == AVSEEK_SIZE ) {
52+ // Size of file-like is typically unknown, since the data is potentially
53+ // streaming.
54+ return AVERROR (EIO );
55+ }
56+ auto self = static_cast <AVIOFileLikeContext*>(opaque);
57+ return self->seek (offset, whence);
58+ }
59+
60+ int AVIOFileLikeContext::writeCallback (
61+ void * opaque,
62+ const uint8_t * buf,
63+ int buf_size) {
64+ auto self = static_cast <AVIOFileLikeContext*>(opaque);
65+ py::gil_scoped_acquire gil;
66+ py::bytes bytes_obj (reinterpret_cast <const char *>(buf), buf_size);
67+ return py::cast<int >(self->fileLike_ ->attr (" write" )(bytes_obj));
68+ }
69+
70+ int AVIOFileLikeContext::read (uint8_t * buf, int size) {
4471 py::gil_scoped_acquire gil;
4572
4673 int totalNumRead = 0 ;
47- while (totalNumRead < buf_size) {
48- int request = buf_size - totalNumRead;
49-
50- // The Python method returns the actual bytes, which we access through the
51- // py::bytes wrapper. That wrapper, however, does not provide us access to
52- // the underlying data pointer, which we need for the memcpy below. So we
53- // convert the bytes to a string_view to get access to the data pointer.
54- // Becauase it's a view and not a copy, it should be cheap.
55- auto bytesRead = static_cast <py::bytes>((*fileLike)->attr (" read" )(request));
74+ while (totalNumRead < size) {
75+ int request = size - totalNumRead;
76+
77+ // The Python method returns the actual bytes, which we access through
78+ // the py::bytes wrapper. That wrapper, however, does not provide us
79+ // access to the underlying data pointer, which we need for the memcpy
80+ // below. So we convert the bytes to a string_view to get access to
81+ // the data pointer. Because it's a view and not a copy, it should be
82+ // cheap.
83+ auto bytesRead = static_cast <py::bytes>(fileLike_->attr (" read" )(request));
5684 auto bytesView = static_cast <std::string_view>(bytesRead);
5785
5886 int numBytesRead = static_cast <int >(bytesView.size ());
@@ -66,33 +94,26 @@ int AVIOFileLikeContext::read(void* opaque, uint8_t* buf, int buf_size) {
6694 request,
6795 " bytes but, received " ,
6896 numBytesRead,
69- " bytes. The given object does not conform to read protocol of file object." );
97+ " bytes. The given object does not conform to read protocol "
98+ " of file object." );
7099
71100 std::memcpy (buf, bytesView.data (), numBytesRead);
72101 buf += numBytesRead;
73102 totalNumRead += numBytesRead;
74103 }
75104
76- return totalNumRead == 0 ? AVERROR_EOF : totalNumRead;
105+ return totalNumRead == 0 ? - 1 : totalNumRead;
77106}
78107
79- int64_t AVIOFileLikeContext::seek (void * opaque, int64_t offset, int whence) {
80- // We do not know the file size.
81- if (whence == AVSEEK_SIZE ) {
82- return AVERROR (EIO );
83- }
84-
85- auto fileLike = static_cast <UniquePyObject*>(opaque);
108+ int64_t AVIOFileLikeContext::seek (int64_t offset, int whence) {
86109 py::gil_scoped_acquire gil;
87- return py::cast<int64_t >((*fileLike) ->attr (" seek" )(offset, whence));
110+ return py::cast<int64_t >(fileLike_ ->attr (" seek" )(offset, whence));
88111}
89112
90- int AVIOFileLikeContext::write (void * opaque, const uint8_t * buf, int buf_size) {
91- auto fileLike = static_cast <UniquePyObject*>(opaque);
92- py::gil_scoped_acquire gil;
93- py::bytes bytes_obj (reinterpret_cast <const char *>(buf), buf_size);
94-
95- return py::cast<int >((*fileLike)->attr (" write" )(bytes_obj));
113+ int64_t AVIOFileLikeContext::getSize () {
114+ // Size of file-like is typically unknown, since the data is potentially
115+ // streaming.
116+ return INT64_MAX ;
96117}
97118
98119} // namespace facebook::torchcodec
0 commit comments