Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
O
opencv
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
opencv
Commits
b6393531
Commit
b6393531
authored
Apr 10, 2015
by
Vadim Pisarevsky
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3912 from kalistratovag:mjpeg_dec
parents
c094c58b
740ae358
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
888 additions
and
2 deletions
+888
-2
cap.cpp
modules/videoio/src/cap.cpp
+18
-0
cap_mjpeg_decoder.cpp
modules/videoio/src/cap_mjpeg_decoder.cpp
+870
-2
No files found.
modules/videoio/src/cap.cpp
View file @
b6393531
...
...
@@ -552,6 +552,20 @@ static Ptr<IVideoCapture> IVideoCapture_create(int index)
}
static
Ptr
<
IVideoCapture
>
IVideoCapture_create
(
const
String
&
filename
)
{
Ptr
<
IVideoCapture
>
capture
;
capture
=
createMotionJpegCapture
(
filename
);
if
(
capture
&&
capture
->
isOpened
())
{
return
capture
;
}
// failed open a camera
return
Ptr
<
IVideoCapture
>
();
}
static
Ptr
<
IVideoWriter
>
IVideoWriter_create
(
const
String
&
filename
,
int
_fourcc
,
double
fps
,
Size
frameSize
,
bool
isColor
)
{
Ptr
<
IVideoWriter
>
iwriter
;
...
...
@@ -582,6 +596,10 @@ VideoCapture::~VideoCapture()
bool
VideoCapture
::
open
(
const
String
&
filename
)
{
if
(
isOpened
())
release
();
icap
=
IVideoCapture_create
(
filename
);
if
(
!
icap
.
empty
())
return
true
;
cap
.
reset
(
cvCreateFileCapture
(
filename
.
c_str
()));
return
isOpened
();
}
...
...
modules/videoio/src/cap_mjpeg_decoder.cpp
View file @
b6393531
...
...
@@ -40,13 +40,881 @@
//M*/
#include "precomp.hpp"
#include <deque>
#include <stdint.h>
namespace
cv
{
Ptr
<
IVideoCapture
>
createMotionJpegCapture
(
const
String
&
)
const
uint32_t
RIFF_CC
=
CV_FOURCC
(
'R'
,
'I'
,
'F'
,
'F'
);
const
uint32_t
LIST_CC
=
CV_FOURCC
(
'L'
,
'I'
,
'S'
,
'T'
);
const
uint32_t
HDRL_CC
=
CV_FOURCC
(
'h'
,
'd'
,
'r'
,
'l'
);
const
uint32_t
AVIH_CC
=
CV_FOURCC
(
'a'
,
'v'
,
'i'
,
'h'
);
const
uint32_t
STRL_CC
=
CV_FOURCC
(
's'
,
't'
,
'r'
,
'l'
);
const
uint32_t
STRH_CC
=
CV_FOURCC
(
's'
,
't'
,
'r'
,
'h'
);
const
uint32_t
VIDS_CC
=
CV_FOURCC
(
'v'
,
'i'
,
'd'
,
's'
);
const
uint32_t
MJPG_CC
=
CV_FOURCC
(
'M'
,
'J'
,
'P'
,
'G'
);
const
uint32_t
MOVI_CC
=
CV_FOURCC
(
'm'
,
'o'
,
'v'
,
'i'
);
const
uint32_t
IDX1_CC
=
CV_FOURCC
(
'i'
,
'd'
,
'x'
,
'1'
);
const
uint32_t
AVI_CC
=
CV_FOURCC
(
'A'
,
'V'
,
'I'
,
' '
);
const
uint32_t
AVIX_CC
=
CV_FOURCC
(
'A'
,
'V'
,
'I'
,
'X'
);
const
uint32_t
JUNK_CC
=
CV_FOURCC
(
'J'
,
'U'
,
'N'
,
'K'
);
const
uint32_t
INFO_CC
=
CV_FOURCC
(
'I'
,
'N'
,
'F'
,
'O'
);
String
fourccToString
(
uint32_t
fourcc
);
String
fourccToString
(
uint32_t
fourcc
)
{
return
format
(
"%c%c%c%c"
,
fourcc
&
255
,
(
fourcc
>>
8
)
&
255
,
(
fourcc
>>
16
)
&
255
,
(
fourcc
>>
24
)
&
255
);
}
#ifndef DWORD
typedef
uint32_t
DWORD
;
#endif
#ifndef WORD
typedef
uint16_t
WORD
;
#endif
#ifndef LONG
typedef
int32_t
LONG
;
#endif
#pragma pack(push, 1)
struct
AviMainHeader
{
DWORD
dwMicroSecPerFrame
;
// The period between video frames
DWORD
dwMaxBytesPerSec
;
// Maximum data rate of the file
DWORD
dwReserved1
;
// 0
DWORD
dwFlags
;
// 0x10 AVIF_HASINDEX: The AVI file has an idx1 chunk containing an index at the end of the file.
DWORD
dwTotalFrames
;
// Field of the main header specifies the total number of frames of data in file.
DWORD
dwInitialFrames
;
// Is used for interleaved files
DWORD
dwStreams
;
// Specifies the number of streams in the file.
DWORD
dwSuggestedBufferSize
;
// Field specifies the suggested buffer size forreading the file
DWORD
dwWidth
;
// Fields specify the width of the AVIfile in pixels.
DWORD
dwHeight
;
// Fields specify the height of the AVIfile in pixels.
DWORD
dwReserved
[
4
];
// 0, 0, 0, 0
};
struct
AviStreamHeader
{
uint32_t
fccType
;
// 'vids', 'auds', 'txts'...
uint32_t
fccHandler
;
// "cvid", "DIB "
DWORD
dwFlags
;
// 0
DWORD
dwPriority
;
// 0
DWORD
dwInitialFrames
;
// 0
DWORD
dwScale
;
// 1
DWORD
dwRate
;
// Fps (dwRate - frame rate for video streams)
DWORD
dwStart
;
// 0
DWORD
dwLength
;
// Frames number (playing time of AVI file as defined by scale and rate)
DWORD
dwSuggestedBufferSize
;
// For reading the stream
DWORD
dwQuality
;
// -1 (encoding quality. If set to -1, drivers use the default quality value)
DWORD
dwSampleSize
;
// 0 means that each frame is in its own chunk
struct
{
short
int
left
;
short
int
top
;
short
int
right
;
short
int
bottom
;
}
rcFrame
;
// If stream has a different size than dwWidth*dwHeight(unused)
};
struct
AviIndex
{
DWORD
ckid
;
DWORD
dwFlags
;
DWORD
dwChunkOffset
;
DWORD
dwChunkLength
;
};
struct
BitmapInfoHeader
{
DWORD
biSize
;
// Write header size of BITMAPINFO header structure
LONG
biWidth
;
// width in pixels
LONG
biHeight
;
// heigth in pixels
WORD
biPlanes
;
// Number of color planes in which the data is stored
WORD
biBitCount
;
// Number of bits per pixel
DWORD
biCompression
;
// Type of compression used (uncompressed: NO_COMPRESSION=0)
DWORD
biSizeImage
;
// Image Buffer. Quicktime needs 3 bytes also for 8-bit png
// (biCompression==NO_COMPRESSION)?0:xDim*yDim*bytesPerPixel;
LONG
biXPelsPerMeter
;
// Horizontal resolution in pixels per meter
LONG
biYPelsPerMeter
;
// Vertical resolution in pixels per meter
DWORD
biClrUsed
;
// 256 (color table size; for 8-bit only)
DWORD
biClrImportant
;
// Specifies that the first x colors of the color table. Are important to the DIB.
};
struct
RiffChunk
{
uint32_t
m_four_cc
;
uint32_t
m_size
;
};
struct
RiffList
{
uint32_t
m_riff_or_list_cc
;
uint32_t
m_size
;
uint32_t
m_list_type_cc
;
};
#pragma pack(pop)
class
MjpegInputStream
{
public
:
MjpegInputStream
();
MjpegInputStream
(
const
String
&
filename
);
~
MjpegInputStream
();
MjpegInputStream
&
read
(
char
*
,
uint64_t
);
MjpegInputStream
&
seekg
(
uint64_t
);
uint64_t
tellg
();
bool
isOpened
()
const
;
bool
open
(
const
String
&
filename
);
void
close
();
operator
bool
();
private
:
bool
m_is_valid
;
FILE
*
m_f
;
};
MjpegInputStream
::
MjpegInputStream
()
:
m_is_valid
(
false
),
m_f
(
0
)
{
}
MjpegInputStream
::
MjpegInputStream
(
const
String
&
filename
)
:
m_is_valid
(
false
),
m_f
(
0
)
{
open
(
filename
);
}
bool
MjpegInputStream
::
isOpened
()
const
{
return
m_f
!=
0
;
}
bool
MjpegInputStream
::
open
(
const
String
&
filename
)
{
close
();
m_f
=
fopen
(
filename
.
c_str
(),
"rb"
);
m_is_valid
=
isOpened
();
return
m_is_valid
;
}
void
MjpegInputStream
::
close
()
{
if
(
isOpened
())
{
m_is_valid
=
false
;
fclose
(
m_f
);
m_f
=
0
;
}
}
MjpegInputStream
&
MjpegInputStream
::
read
(
char
*
buf
,
uint64_t
count
)
{
if
(
isOpened
())
{
m_is_valid
=
(
count
==
fread
((
void
*
)
buf
,
1
,
(
size_t
)
count
,
m_f
));
}
return
*
this
;
}
MjpegInputStream
&
MjpegInputStream
::
seekg
(
uint64_t
pos
)
{
m_is_valid
=
(
fseek
(
m_f
,
(
long
)
pos
,
SEEK_SET
)
==
0
);
return
*
this
;
}
uint64_t
MjpegInputStream
::
tellg
()
{
return
ftell
(
m_f
);
}
MjpegInputStream
::
operator
bool
()
{
return
m_is_valid
;
}
MjpegInputStream
::~
MjpegInputStream
()
{
close
();
}
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
AviMainHeader
&
avih
);
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
AviStreamHeader
&
strh
);
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
BitmapInfoHeader
&
bmph
);
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
RiffList
&
riff_list
);
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
RiffChunk
&
riff_chunk
);
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
AviIndex
&
idx1
);
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
AviMainHeader
&
avih
)
{
is
.
read
((
char
*
)(
&
avih
),
sizeof
(
AviMainHeader
));
return
is
;
}
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
AviStreamHeader
&
strh
)
{
is
.
read
((
char
*
)(
&
strh
),
sizeof
(
AviStreamHeader
));
return
is
;
}
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
BitmapInfoHeader
&
bmph
)
{
is
.
read
((
char
*
)(
&
bmph
),
sizeof
(
BitmapInfoHeader
));
return
is
;
}
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
RiffList
&
riff_list
)
{
is
.
read
((
char
*
)(
&
riff_list
),
sizeof
(
riff_list
));
return
is
;
}
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
RiffChunk
&
riff_chunk
)
{
is
.
read
((
char
*
)(
&
riff_chunk
),
sizeof
(
riff_chunk
));
return
is
;
}
MjpegInputStream
&
operator
>>
(
MjpegInputStream
&
is
,
AviIndex
&
idx1
)
{
is
.
read
((
char
*
)(
&
idx1
),
sizeof
(
idx1
));
return
is
;
}
/*
AVI struct:
RIFF ('AVI '
LIST ('hdrl'
'avih'(<Main AVI Header>)
LIST ('strl'
'strh'(<Stream header>)
'strf'(<Stream format>)
[ 'strd'(<Additional header data>) ]
[ 'strn'(<Stream name>) ]
[ 'indx'(<Odml index data>) ]
...
)
[LIST ('strl' ...)]
[LIST ('strl' ...)]
...
[LIST ('odml'
'dmlh'(<ODML header data>)
...
)
]
...
)
[LIST ('INFO' ...)]
[JUNK]
LIST ('movi'
{{xxdb|xxdc|xxpc|xxwb}(<Data>) | LIST ('rec '
{xxdb|xxdc|xxpc|xxwb}(<Data>)
{xxdb|xxdc|xxpc|xxwb}(<Data>)
...
)
...
}
...
)
['idx1' (<AVI Index>) ]
)
{xxdb|xxdc|xxpc|xxwb}
xx - stream number: 00, 01, 02, ...
db - uncompressed video frame
dc - commpressed video frame
pc - palette change
wb - audio frame
JUNK section may pad any data section and must be ignored
*/
typedef
std
::
deque
<
std
::
pair
<
uint64_t
,
uint32_t
>
>
frame_list
;
typedef
frame_list
::
iterator
frame_iterator
;
//Represents single MJPEG video stream within single AVI/AVIX entry
//Multiple video streams within single AVI/AVIX entry are not supported
//ODML index is not supported
class
AviMjpegStream
{
public
:
AviMjpegStream
();
//stores founded frames in m_frame_list which be accessed via getFrames
bool
parseAvi
(
MjpegInputStream
&
in_str
);
//stores founded frames in in_frame_list. getFrames() would return empty list
bool
parseAvi
(
MjpegInputStream
&
in_str
,
frame_list
&
in_frame_list
);
size_t
getFramesCount
();
frame_list
&
getFrames
();
uint32_t
getWidth
();
uint32_t
getHeight
();
double
getFps
();
protected
:
bool
parseAviWithFrameList
(
MjpegInputStream
&
in_str
,
frame_list
&
in_frame_list
);
void
skipJunk
(
RiffChunk
&
chunk
,
MjpegInputStream
&
in_str
);
void
skipJunk
(
RiffList
&
list
,
MjpegInputStream
&
in_str
);
bool
parseHdrlList
(
MjpegInputStream
&
in_str
);
bool
parseIndex
(
MjpegInputStream
&
in_str
,
uint32_t
index_size
,
frame_list
&
in_frame_list
);
bool
parseMovi
(
MjpegInputStream
&
in_str
,
frame_list
&
in_frame_list
);
bool
parseStrl
(
MjpegInputStream
&
in_str
,
uint8_t
stream_id
);
bool
parseInfo
(
MjpegInputStream
&
in_str
);
void
printError
(
MjpegInputStream
&
in_str
,
RiffList
&
list
,
uint32_t
expected_fourcc
);
void
printError
(
MjpegInputStream
&
in_str
,
RiffChunk
&
chunk
,
uint32_t
expected_fourcc
);
uint32_t
m_stream_id
;
uint64_t
m_movi_start
;
uint64_t
m_movi_end
;
frame_list
m_frame_list
;
uint32_t
m_width
;
uint32_t
m_height
;
double
m_fps
;
bool
m_is_indx_present
;
};
AviMjpegStream
::
AviMjpegStream
()
:
m_stream_id
(
0
),
m_movi_end
(
0
),
m_width
(
0
),
m_height
(
0
),
m_fps
(
0
),
m_is_indx_present
(
false
)
{
}
size_t
AviMjpegStream
::
getFramesCount
()
{
return
m_frame_list
.
size
();
}
frame_list
&
AviMjpegStream
::
getFrames
()
{
return
m_frame_list
;
}
uint32_t
AviMjpegStream
::
getWidth
()
{
return
m_width
;
}
uint32_t
AviMjpegStream
::
getHeight
()
{
return
m_height
;
}
double
AviMjpegStream
::
getFps
()
{
return
m_fps
;
}
void
AviMjpegStream
::
printError
(
MjpegInputStream
&
in_str
,
RiffList
&
list
,
uint32_t
expected_fourcc
)
{
if
(
!
in_str
)
{
fprintf
(
stderr
,
"Unexpected end of file while searching for %s list
\n
"
,
fourccToString
(
expected_fourcc
).
c_str
());
}
else
if
(
list
.
m_riff_or_list_cc
!=
LIST_CC
)
{
fprintf
(
stderr
,
"Unexpected element. Expected: %s. Got: %s.
\n
"
,
fourccToString
(
LIST_CC
).
c_str
(),
fourccToString
(
list
.
m_riff_or_list_cc
).
c_str
());
}
else
{
fprintf
(
stderr
,
"Unexpected list type. Expected: %s. Got: %s.
\n
"
,
fourccToString
(
expected_fourcc
).
c_str
(),
fourccToString
(
list
.
m_list_type_cc
).
c_str
());
}
}
void
AviMjpegStream
::
printError
(
MjpegInputStream
&
in_str
,
RiffChunk
&
chunk
,
uint32_t
expected_fourcc
)
{
if
(
!
in_str
)
{
fprintf
(
stderr
,
"Unexpected end of file while searching for %s chunk
\n
"
,
fourccToString
(
expected_fourcc
).
c_str
());
}
else
{
fprintf
(
stderr
,
"Unexpected element. Expected: %s. Got: %s.
\n
"
,
fourccToString
(
expected_fourcc
).
c_str
(),
fourccToString
(
chunk
.
m_four_cc
).
c_str
());
}
}
bool
AviMjpegStream
::
parseMovi
(
MjpegInputStream
&
,
frame_list
&
)
{
//not implemented
return
true
;
}
bool
AviMjpegStream
::
parseInfo
(
MjpegInputStream
&
)
{
//not implemented
return
true
;
}
bool
AviMjpegStream
::
parseIndex
(
MjpegInputStream
&
in_str
,
uint32_t
index_size
,
frame_list
&
in_frame_list
)
{
uint64_t
index_end
=
in_str
.
tellg
();
index_end
+=
index_size
;
bool
result
=
false
;
while
(
in_str
&&
(
in_str
.
tellg
()
<
index_end
))
{
AviIndex
idx1
;
in_str
>>
idx1
;
if
(
idx1
.
ckid
==
m_stream_id
)
{
uint64_t
absolute_pos
=
m_movi_start
+
idx1
.
dwChunkOffset
;
if
(
absolute_pos
<
m_movi_end
)
{
in_frame_list
.
push_back
(
std
::
make_pair
(
absolute_pos
,
idx1
.
dwChunkLength
));
}
else
{
//unsupported case
fprintf
(
stderr
,
"Frame offset points outside movi section.
\n
"
);
}
}
result
=
true
;
}
return
result
;
}
bool
AviMjpegStream
::
parseStrl
(
MjpegInputStream
&
in_str
,
uint8_t
stream_id
)
{
RiffChunk
strh
;
in_str
>>
strh
;
if
(
in_str
&&
strh
.
m_four_cc
==
STRH_CC
)
{
uint64_t
next_strl_list
=
in_str
.
tellg
();
next_strl_list
+=
strh
.
m_size
;
AviStreamHeader
strm_hdr
;
in_str
>>
strm_hdr
;
if
(
strm_hdr
.
fccType
==
VIDS_CC
&&
strm_hdr
.
fccHandler
==
MJPG_CC
)
{
uint8_t
first_digit
=
(
stream_id
/
10
)
+
'0'
;
uint8_t
second_digit
=
(
stream_id
%
10
)
+
'0'
;
if
(
m_stream_id
==
0
)
{
m_stream_id
=
CV_FOURCC
(
first_digit
,
second_digit
,
'd'
,
'c'
);
m_fps
=
double
(
strm_hdr
.
dwRate
)
/
strm_hdr
.
dwScale
;
}
else
{
//second mjpeg video stream found which is not supported
fprintf
(
stderr
,
"More than one video stream found within AVI/AVIX list. Stream %c%cdc would be ignored
\n
"
,
first_digit
,
second_digit
);
}
return
true
;
}
}
return
false
;
}
void
AviMjpegStream
::
skipJunk
(
RiffChunk
&
chunk
,
MjpegInputStream
&
in_str
)
{
if
(
chunk
.
m_four_cc
==
JUNK_CC
)
{
in_str
.
seekg
(
in_str
.
tellg
()
+
chunk
.
m_size
);
in_str
>>
chunk
;
}
}
void
AviMjpegStream
::
skipJunk
(
RiffList
&
list
,
MjpegInputStream
&
in_str
)
{
if
(
list
.
m_riff_or_list_cc
==
JUNK_CC
)
{
//JUNK chunk is 4 bytes less than LIST
in_str
.
seekg
(
in_str
.
tellg
()
+
list
.
m_size
-
4
);
in_str
>>
list
;
}
}
bool
AviMjpegStream
::
parseHdrlList
(
MjpegInputStream
&
in_str
)
{
bool
result
=
false
;
RiffChunk
avih
;
in_str
>>
avih
;
if
(
in_str
&&
avih
.
m_four_cc
==
AVIH_CC
)
{
uint64_t
next_strl_list
=
in_str
.
tellg
();
next_strl_list
+=
avih
.
m_size
;
AviMainHeader
avi_hdr
;
in_str
>>
avi_hdr
;
if
(
in_str
)
{
m_is_indx_present
=
((
avi_hdr
.
dwFlags
&
0x10
)
!=
0
);
DWORD
number_of_streams
=
avi_hdr
.
dwStreams
;
m_width
=
avi_hdr
.
dwWidth
;
m_height
=
avi_hdr
.
dwWidth
;
//the number of strl lists must be equal to number of streams specified in main avi header
for
(
DWORD
i
=
0
;
i
<
number_of_streams
;
++
i
)
{
in_str
.
seekg
(
next_strl_list
);
RiffList
strl_list
;
in_str
>>
strl_list
;
if
(
in_str
&&
strl_list
.
m_riff_or_list_cc
==
LIST_CC
&&
strl_list
.
m_list_type_cc
==
STRL_CC
)
{
next_strl_list
=
in_str
.
tellg
();
//RiffList::m_size includes fourCC field which we have already read
next_strl_list
+=
(
strl_list
.
m_size
-
4
);
result
=
parseStrl
(
in_str
,
(
uint8_t
)
i
);
}
else
{
printError
(
in_str
,
strl_list
,
STRL_CC
);
}
}
}
}
else
{
printError
(
in_str
,
avih
,
AVIH_CC
);
}
return
result
;
}
bool
AviMjpegStream
::
parseAviWithFrameList
(
MjpegInputStream
&
in_str
,
frame_list
&
in_frame_list
)
{
RiffList
hdrl_list
;
in_str
>>
hdrl_list
;
if
(
in_str
&&
hdrl_list
.
m_riff_or_list_cc
==
LIST_CC
&&
hdrl_list
.
m_list_type_cc
==
HDRL_CC
)
{
uint64_t
next_list
=
in_str
.
tellg
();
//RiffList::m_size includes fourCC field which we have already read
next_list
+=
(
hdrl_list
.
m_size
-
4
);
//parseHdrlList sets m_is_indx_present flag which would be used later
if
(
parseHdrlList
(
in_str
))
{
in_str
.
seekg
(
next_list
);
RiffList
some_list
;
in_str
>>
some_list
;
//an optional section INFO
if
(
in_str
&&
some_list
.
m_riff_or_list_cc
==
LIST_CC
&&
some_list
.
m_list_type_cc
==
INFO_CC
)
{
next_list
=
in_str
.
tellg
();
//RiffList::m_size includes fourCC field which we have already read
next_list
+=
(
some_list
.
m_size
-
4
);
parseInfo
(
in_str
);
in_str
.
seekg
(
next_list
);
in_str
>>
some_list
;
}
//an optional section JUNK
skipJunk
(
some_list
,
in_str
);
//we are expecting to find here movi list. Must present in avi
if
(
in_str
&&
some_list
.
m_riff_or_list_cc
==
LIST_CC
&&
some_list
.
m_list_type_cc
==
MOVI_CC
)
{
bool
is_index_found
=
false
;
m_movi_start
=
in_str
.
tellg
();
m_movi_start
-=
4
;
m_movi_end
=
m_movi_start
+
some_list
.
m_size
;
//if m_is_indx_present is set to true we should find index
if
(
m_is_indx_present
)
{
//we are expecting to find index section after movi list
uint32_t
indx_pos
=
(
uint32_t
)
m_movi_start
+
4
;
indx_pos
+=
(
some_list
.
m_size
-
4
);
in_str
.
seekg
(
indx_pos
);
RiffChunk
index_chunk
;
in_str
>>
index_chunk
;
if
(
in_str
&&
index_chunk
.
m_four_cc
==
IDX1_CC
)
{
is_index_found
=
parseIndex
(
in_str
,
index_chunk
.
m_size
,
in_frame_list
);
//we are not going anywhere else
}
else
{
printError
(
in_str
,
index_chunk
,
IDX1_CC
);
}
}
//index not present or we were not able to find it
//parsing movi list
if
(
!
is_index_found
)
{
//not implemented
parseMovi
(
in_str
,
in_frame_list
);
fprintf
(
stderr
,
"Failed to parse avi: index was not found
\n
"
);
//we are not going anywhere else
}
}
else
{
printError
(
in_str
,
some_list
,
MOVI_CC
);
}
}
}
else
{
printError
(
in_str
,
hdrl_list
,
HDRL_CC
);
}
return
in_frame_list
.
size
()
>
0
;
}
bool
AviMjpegStream
::
parseAvi
(
MjpegInputStream
&
in_str
,
frame_list
&
in_frame_list
)
{
return
parseAviWithFrameList
(
in_str
,
in_frame_list
);
}
bool
AviMjpegStream
::
parseAvi
(
MjpegInputStream
&
in_str
)
{
return
parseAviWithFrameList
(
in_str
,
m_frame_list
);
}
class
MotionJpegCapture
:
public
IVideoCapture
{
public
:
virtual
~
MotionJpegCapture
();
virtual
double
getProperty
(
int
)
const
;
virtual
bool
setProperty
(
int
,
double
);
virtual
bool
grabFrame
();
virtual
bool
retrieveFrame
(
int
,
OutputArray
);
virtual
bool
isOpened
()
const
;
virtual
int
getCaptureDomain
()
{
return
CAP_ANY
;
}
// Return the type of the capture object: CAP_VFW, etc...
MotionJpegCapture
(
const
String
&
);
bool
open
(
const
String
&
);
void
close
();
protected
:
bool
parseRiff
(
MjpegInputStream
&
in_str
);
inline
uint64_t
getFramePos
()
const
;
std
::
vector
<
char
>
readFrame
(
frame_iterator
it
);
MjpegInputStream
m_file_stream
;
bool
m_is_first_frame
;
frame_list
m_mjpeg_frames
;
frame_iterator
m_frame_iterator
;
Mat
m_current_frame
;
//frame width/height and fps could be different for
//each frame/stream. At the moment we suppose that they
//stays the same within single avi file.
uint32_t
m_frame_width
;
uint32_t
m_frame_height
;
double
m_fps
;
};
uint64_t
MotionJpegCapture
::
getFramePos
()
const
{
if
(
m_is_first_frame
)
return
0
;
if
(
m_frame_iterator
==
m_mjpeg_frames
.
end
())
return
m_mjpeg_frames
.
size
();
return
m_frame_iterator
-
m_mjpeg_frames
.
begin
()
+
1
;
}
bool
MotionJpegCapture
::
setProperty
(
int
property
,
double
value
)
{
if
(
property
==
CAP_PROP_POS_FRAMES
)
{
if
(
int
(
value
)
==
0
)
{
m_is_first_frame
=
true
;
m_frame_iterator
=
m_mjpeg_frames
.
end
();
return
true
;
}
else
if
(
m_mjpeg_frames
.
size
()
>
value
)
{
m_frame_iterator
=
m_mjpeg_frames
.
begin
()
+
int
(
value
-
1
);
m_is_first_frame
=
false
;
return
true
;
}
}
return
false
;
}
double
MotionJpegCapture
::
getProperty
(
int
property
)
const
{
switch
(
property
)
{
case
CAP_PROP_POS_FRAMES
:
return
(
double
)
getFramePos
();
case
CAP_PROP_POS_AVI_RATIO
:
return
double
(
getFramePos
())
/
m_mjpeg_frames
.
size
();
case
CAP_PROP_FRAME_WIDTH
:
return
(
double
)
m_frame_width
;
case
CAP_PROP_FRAME_HEIGHT
:
return
(
double
)
m_frame_height
;
case
CAP_PROP_FPS
:
return
m_fps
;
case
CAP_PROP_FOURCC
:
return
(
double
)
CV_FOURCC
(
'M'
,
'J'
,
'P'
,
'G'
);
case
CAP_PROP_FRAME_COUNT
:
return
(
double
)
m_mjpeg_frames
.
size
();
case
CAP_PROP_FORMAT
:
return
0
;
default
:
return
0
;
}
}
std
::
vector
<
char
>
MotionJpegCapture
::
readFrame
(
frame_iterator
it
)
{
m_file_stream
.
seekg
(
it
->
first
);
RiffChunk
chunk
;
m_file_stream
>>
chunk
;
std
::
vector
<
char
>
result
;
result
.
reserve
(
chunk
.
m_size
);
result
.
resize
(
chunk
.
m_size
);
m_file_stream
.
read
(
result
.
data
(),
chunk
.
m_size
);
return
result
;
}
bool
MotionJpegCapture
::
grabFrame
()
{
if
(
isOpened
())
{
if
(
m_is_first_frame
)
{
m_is_first_frame
=
false
;
m_frame_iterator
=
m_mjpeg_frames
.
begin
();
}
else
{
++
m_frame_iterator
;
}
}
return
m_frame_iterator
!=
m_mjpeg_frames
.
end
();
}
bool
MotionJpegCapture
::
retrieveFrame
(
int
,
OutputArray
output_frame
)
{
if
(
m_frame_iterator
!=
m_mjpeg_frames
.
end
())
{
std
::
vector
<
char
>
data
=
readFrame
(
m_frame_iterator
);
if
(
data
.
size
())
{
m_current_frame
=
imdecode
(
data
,
CV_LOAD_IMAGE_ANYDEPTH
|
CV_LOAD_IMAGE_COLOR
);
}
m_current_frame
.
copyTo
(
output_frame
);
return
true
;
}
return
false
;
}
MotionJpegCapture
::~
MotionJpegCapture
()
{
close
();
}
MotionJpegCapture
::
MotionJpegCapture
(
const
String
&
filename
)
{
open
(
filename
);
}
bool
MotionJpegCapture
::
isOpened
()
const
{
return
m_mjpeg_frames
.
size
()
>
0
;
}
void
MotionJpegCapture
::
close
()
{
m_file_stream
.
close
();
m_frame_iterator
=
m_mjpeg_frames
.
end
();
}
bool
MotionJpegCapture
::
open
(
const
String
&
filename
)
{
close
();
m_file_stream
.
open
(
filename
);
m_frame_iterator
=
m_mjpeg_frames
.
end
();
m_is_first_frame
=
true
;
if
(
!
parseRiff
(
m_file_stream
))
{
close
();
}
return
isOpened
();
}
bool
MotionJpegCapture
::
parseRiff
(
MjpegInputStream
&
in_str
)
{
bool
result
=
false
;
while
(
in_str
)
{
RiffList
riff_list
;
in_str
>>
riff_list
;
if
(
in_str
&&
riff_list
.
m_riff_or_list_cc
==
RIFF_CC
&&
((
riff_list
.
m_list_type_cc
==
AVI_CC
)
|
(
riff_list
.
m_list_type_cc
==
AVIX_CC
))
)
{
uint64_t
next_riff
=
in_str
.
tellg
();
//RiffList::m_size includes fourCC field which we have already read
next_riff
+=
(
riff_list
.
m_size
-
4
);
AviMjpegStream
mjpeg_video_stream
;
bool
is_parsed
=
mjpeg_video_stream
.
parseAvi
(
in_str
,
m_mjpeg_frames
);
result
=
result
||
is_parsed
;
if
(
is_parsed
)
{
m_frame_width
=
mjpeg_video_stream
.
getWidth
();
m_frame_height
=
mjpeg_video_stream
.
getHeight
();
m_fps
=
mjpeg_video_stream
.
getFps
();
}
in_str
.
seekg
(
next_riff
);
}
else
{
break
;
}
}
return
result
;
}
Ptr
<
IVideoCapture
>
createMotionJpegCapture
(
const
String
&
filename
)
{
return
Ptr
<
IVideoCapture
>
();
Ptr
<
MotionJpegCapture
>
mjdecoder
(
new
MotionJpegCapture
(
filename
));
if
(
mjdecoder
->
isOpened
()
)
return
mjdecoder
;
return
Ptr
<
MotionJpegCapture
>
();
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment