Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Submit feedback
Sign in / Register
Toggle navigation
J
jami-daemon
Project overview
Project overview
Details
Activity
Releases
Cycle Analytics
Insights
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Locked Files
Issues
87
Issues
87
List
Boards
Labels
Milestones
Security & Compliance
Security & Compliance
Dependency List
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
savoirfairelinux
jami-daemon
Commits
693c8725
Commit
693c8725
authored
Aug 06, 2019
by
Philippe Gorley
Committed by
Philippe Gorley
Aug 07, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
media: split demuxer and decoder
Change-Id: I237a3c4110d3b553d2b9cee99abbede4b10a80d2
parent
dd787db8
Changes
14
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
346 additions
and
391 deletions
+346
-391
src/media/audio/audio_input.cpp
src/media/audio/audio_input.cpp
+13
-18
src/media/audio/audio_receive_thread.cpp
src/media/audio/audio_receive_thread.cpp
+6
-28
src/media/audio/audiobuffer.cpp
src/media/audio/audiobuffer.cpp
+7
-7
src/media/audio/sound/audiofile.cpp
src/media/audio/sound/audiofile.cpp
+8
-32
src/media/media_buffer.h
src/media/media_buffer.h
+2
-0
src/media/media_decoder.cpp
src/media/media_decoder.cpp
+137
-145
src/media/media_decoder.h
src/media/media_decoder.h
+112
-64
src/media/video/video_base.cpp
src/media/video/video_base.cpp
+8
-0
src/media/video/video_base.h
src/media/video/video_base.h
+1
-0
src/media/video/video_input.cpp
src/media/video/video_input.cpp
+14
-34
src/media/video/video_receive_thread.cpp
src/media/video/video_receive_thread.cpp
+13
-50
src/media/video/video_receive_thread.h
src/media/video/video_receive_thread.h
+1
-1
src/observer.h
src/observer.h
+15
-0
test/unitTest/media/test_media_decoder.cpp
test/unitTest/media/test_media_decoder.cpp
+9
-12
No files found.
src/media/audio/audio_input.cpp
View file @
693c8725
...
...
@@ -116,23 +116,15 @@ AudioInput::readFromFile()
{
if
(
!
decoder_
)
return
;
auto
frame
=
std
::
make_unique
<
AudioFrame
>
();
const
auto
ret
=
decoder_
->
decode
(
*
frame
);
switch
(
ret
)
{
case
MediaDecoder
:
:
Status
::
ReadError
:
case
MediaDecoder
:
:
Status
::
DecodeError
:
JAMI_ERR
()
<<
"Failed to decode frame"
;
const
auto
ret
=
decoder_
->
decode
();
switch
(
ret
)
{
case
MediaDemuxer
:
:
Status
::
Success
:
break
;
case
MediaDecoder
:
:
Status
::
RestartRequired
:
case
MediaDecoder
:
:
Status
::
EOFError
:
case
MediaDemuxer
:
:
Status
::
EndOfFile
:
createDecoder
();
break
;
case
MediaDecoder
:
:
Status
::
FrameFinished
:
fileBuf_
->
put
(
std
::
move
(
frame
));
break
;
case
MediaDecoder
:
:
Status
::
Success
:
default:
case
MediaDemuxer
:
:
Status
::
ReadError
:
JAMI_ERR
()
<<
"Failed to decode frame"
;
break
;
}
}
...
...
@@ -247,11 +239,14 @@ AudioInput::createDecoder()
return
false
;
}
auto
decoder
=
std
::
make_unique
<
MediaDecoder
>
([
this
](
std
::
shared_ptr
<
MediaFrame
>&&
frame
)
{
fileBuf_
->
put
(
std
::
move
(
std
::
static_pointer_cast
<
AudioFrame
>
(
frame
)));
});
// NOTE don't emulate rate, file is read as frames are needed
auto
decoder
=
std
::
make_unique
<
MediaDecoder
>
();
decoder
->
setInterruptCallback
(
[](
void
*
data
)
->
int
{
return
not
static_cast
<
AudioInput
*>
(
data
)
->
isCapturing
();
},
this
);
[](
void
*
data
)
->
int
{
return
not
static_cast
<
AudioInput
*>
(
data
)
->
isCapturing
();
},
this
);
if
(
decoder
->
openInput
(
devOpts_
)
<
0
)
{
JAMI_ERR
()
<<
"Could not open input '"
<<
devOpts_
.
input
<<
"'"
;
...
...
@@ -259,7 +254,7 @@ AudioInput::createDecoder()
return
false
;
}
if
(
decoder
->
setup
FromAudioData
()
<
0
)
{
if
(
decoder
->
setup
Audio
()
<
0
)
{
JAMI_ERR
()
<<
"Could not setup decoder for '"
<<
devOpts_
.
input
<<
"'"
;
foundDevOpts
(
devOpts_
);
return
false
;
...
...
src/media/audio/audio_receive_thread.cpp
View file @
693c8725
...
...
@@ -57,7 +57,10 @@ AudioReceiveThread::~AudioReceiveThread()
bool
AudioReceiveThread
::
setup
()
{
audioDecoder_
.
reset
(
new
MediaDecoder
());
audioDecoder_
.
reset
(
new
MediaDecoder
([
this
](
std
::
shared_ptr
<
MediaFrame
>&&
frame
)
mutable
{
notify
(
frame
);
ringbuffer_
->
put
(
std
::
move
(
std
::
static_pointer_cast
<
AudioFrame
>
(
frame
)));
}));
audioDecoder_
->
setInterruptCallback
(
interruptCb
,
this
);
// custom_io so the SDP demuxer will not open any UDP connections
...
...
@@ -78,11 +81,10 @@ AudioReceiveThread::setup()
// Now replace our custom AVIOContext with one that will read packets
audioDecoder_
->
setIOContext
(
demuxContext_
.
get
());
if
(
audioDecoder_
->
setup
FromAudioData
())
{
if
(
audioDecoder_
->
setup
Audio
())
{
JAMI_ERR
(
"decoder IO startup failed"
);
return
false
;
}
Smartools
::
getInstance
().
setRemoteAudioCodec
(
audioDecoder_
->
getDecoderName
());
ringbuffer_
=
Manager
::
instance
().
getRingBufferPool
().
getRingBuffer
(
id_
);
...
...
@@ -92,31 +94,7 @@ AudioReceiveThread::setup()
void
AudioReceiveThread
::
process
()
{
auto
decodedFrame
=
std
::
make_shared
<
AudioFrame
>
();
switch
(
audioDecoder_
->
decode
(
*
decodedFrame
))
{
case
MediaDecoder
:
:
Status
::
FrameFinished
:
notify
(
std
::
static_pointer_cast
<
MediaFrame
>
(
decodedFrame
));
ringbuffer_
->
put
(
std
::
move
(
decodedFrame
));
return
;
case
MediaDecoder
:
:
Status
::
DecodeError
:
JAMI_WARN
(
"decoding failure, trying to reset decoder..."
);
if
(
not
setup
())
{
JAMI_ERR
(
"fatal error, rx thread re-setup failed"
);
loop_
.
stop
();
}
else
if
(
not
audioDecoder_
->
setupFromAudioData
())
{
JAMI_ERR
(
"fatal error, a-decoder setup failed"
);
loop_
.
stop
();
}
break
;
case
MediaDecoder
:
:
Status
::
ReadError
:
JAMI_ERR
(
"fatal error, read failed"
);
loop_
.
stop
();
break
;
case
MediaDecoder
:
:
Status
::
Success
:
case
MediaDecoder
:
:
Status
::
EOFError
:
default:
break
;
}
audioDecoder_
->
decode
();
}
void
...
...
src/media/audio/audiobuffer.cpp
View file @
693c8725
...
...
@@ -317,14 +317,14 @@ AudioBuffer::append(const AudioFrame& audioFrame)
setFormat
(
newFormat
);
}
AudioBuffer
toAppend
(
frame
->
nb_samples
,
{(
unsigned
)
frame
->
sample_rate
,
(
unsigned
)
frame
->
channels
});
toAppend
.
deinterleave
(
reinterpret_cast
<
const
AudioSample
*>
(
frame
->
extended_data
[
0
]),
frame
->
nb_samples
,
frame
->
channels
);
auto
f
=
frames
();
auto
newSize
=
f
+
frame
->
nb_samples
;
resize
(
newSize
);
for
(
size_t
c
=
0
;
c
<
samples_
.
size
();
++
c
)
{
samples_
[
c
].
insert
(
samples_
[
c
].
end
(),
toAppend
.
samples_
[
c
].
begin
(),
toAppend
.
samples_
[
c
].
end
());
}
auto
in
=
reinterpret_cast
<
const
AudioSample
*>
(
frame
->
extended_data
[
0
]);
for
(
unsigned
c
=
channels
();
f
<
newSize
;
f
++
)
for
(
unsigned
j
=
0
;
j
<
c
;
j
++
)
samples_
[
j
][
f
]
=
*
in
++
;
return
0
;
}
...
...
src/media/audio/sound/audiofile.cpp
View file @
693c8725
...
...
@@ -59,46 +59,22 @@ AudioFile::onBufferFinish()
AudioFile
::
AudioFile
(
const
std
::
string
&
fileName
,
unsigned
int
sampleRate
)
:
AudioLoop
(
sampleRate
),
filepath_
(
fileName
),
updatePlaybackScale_
(
0
)
{
auto
decoder
=
std
::
make_unique
<
MediaDecoder
>
();
const
auto
&
format
=
getFormat
();
auto
buf
=
std
::
make_unique
<
AudioBuffer
>
(
0
,
format
);
Resampler
r
{};
auto
decoder
=
std
::
make_unique
<
MediaDecoder
>
([
this
,
&
r
,
&
format
,
&
buf
](
const
std
::
shared_ptr
<
MediaFrame
>&
frame
)
mutable
{
buf
->
append
(
*
r
.
resample
(
std
::
static_pointer_cast
<
AudioFrame
>
(
frame
),
format
));
});
DeviceParams
dev
;
dev
.
input
=
fileName
;
if
(
decoder
->
openInput
(
dev
)
<
0
)
throw
AudioFileException
(
"File could not be opened: "
+
fileName
);
if
(
decoder
->
setup
FromAudioData
()
<
0
)
if
(
decoder
->
setup
Audio
()
<
0
)
throw
AudioFileException
(
"Decoder setup failed: "
+
fileName
);
auto
resampler
=
std
::
make_unique
<
Resampler
>
();
const
auto
&
format
=
getFormat
();
auto
buf
=
std
::
make_unique
<
AudioBuffer
>
(
0
,
format
);
bool
done
=
false
;
while
(
!
done
)
{
AudioFrame
input
;
AudioFrame
output
;
auto
resampled
=
output
.
pointer
();
switch
(
decoder
->
decode
(
input
))
{
case
MediaDecoder
:
:
Status
::
FrameFinished
:
resampled
->
sample_rate
=
format
.
sample_rate
;
resampled
->
channel_layout
=
av_get_default_channel_layout
(
format
.
nb_channels
);
resampled
->
channels
=
format
.
nb_channels
;
resampled
->
format
=
format
.
sampleFormat
;
if
(
resampler
->
resample
(
input
.
pointer
(),
resampled
)
<
0
)
throw
AudioFileException
(
"Frame could not be resampled"
);
if
(
buf
->
append
(
output
)
<
0
)
throw
AudioFileException
(
"Error while decoding: "
+
fileName
);
break
;
case
MediaDecoder
:
:
Status
::
DecodeError
:
case
MediaDecoder
:
:
Status
::
ReadError
:
throw
AudioFileException
(
"File cannot be decoded: "
+
fileName
);
case
MediaDecoder
:
:
Status
::
EOFError
:
done
=
true
;
break
;
case
MediaDecoder
:
:
Status
::
Success
:
default:
break
;
}
}
while
(
decoder
->
decode
()
!=
MediaDemuxer
::
Status
::
EndOfFile
);
delete
buffer_
;
buffer_
=
buf
.
release
();
...
...
src/media/media_buffer.h
View file @
693c8725
...
...
@@ -22,6 +22,7 @@
#include "config.h"
#include "videomanager_interface.h"
#include "observer.h"
#include <memory>
#include <functional>
...
...
@@ -38,6 +39,7 @@ namespace jami {
using
MediaFrame
=
DRing
::
MediaFrame
;
using
AudioFrame
=
DRing
::
AudioFrame
;
using
MediaObserver
=
std
::
function
<
void
(
std
::
shared_ptr
<
MediaFrame
>&&
)
>
;
#ifdef ENABLE_VIDEO
...
...
src/media/media_decoder.cpp
View file @
693c8725
This diff is collapsed.
Click to expand it.
src/media/media_decoder.h
View file @
693c8725
...
...
@@ -22,17 +22,22 @@
#include "config.h"
#include "rational.h"
#include "observer.h"
#ifdef ENABLE_VIDEO
#include "video/video_base.h"
#include "video/video_scaler.h"
#endif // ENABLE_VIDEO
#ifdef RING_ACCEL
#include "video/accel.h"
#endif
#include "logger.h"
#include "audio/audiobuffer.h"
#include "media_device.h"
#include "media_stream.h"
#include "rational.h"
#include "noncopyable.h"
#include <map>
...
...
@@ -60,85 +65,128 @@ struct AudioFormat;
class
RingBuffer
;
class
Resampler
;
class
MediaIOHandle
;
class
MediaDecoder
;
class
MediaDemuxer
{
public:
MediaDemuxer
();
~
MediaDemuxer
();
enum
class
Status
{
Success
,
EndOfFile
,
ReadError
};
using
StreamCallback
=
std
::
function
<
void
(
AVPacket
&
)
>
;
int
openInput
(
const
DeviceParams
&
);
void
setInterruptCallback
(
int
(
*
cb
)(
void
*
),
void
*
opaque
);
void
setIOContext
(
MediaIOHandle
*
ioctx
);
void
findStreamInfo
();
int
selectStream
(
AVMediaType
type
);
void
setStreamCallback
(
unsigned
stream
,
StreamCallback
cb
=
{})
{
if
(
streams_
.
size
()
<=
stream
)
streams_
.
resize
(
stream
+
1
);
streams_
[
stream
]
=
std
::
move
(
cb
);
}
AVStream
*
getStream
(
unsigned
stream
)
{
if
(
stream
>=
inputCtx_
->
nb_streams
)
throw
std
::
invalid_argument
(
"Invalid stream index"
);
return
inputCtx_
->
streams
[
stream
];
}
Status
decode
();
private:
bool
streamInfoFound_
{
false
};
AVFormatContext
*
inputCtx_
=
nullptr
;
std
::
vector
<
StreamCallback
>
streams_
;
int64_t
startTime_
;
DeviceParams
inputParams_
;
AVDictionary
*
options_
=
nullptr
;
};
class
MediaDecoder
{
public:
enum
class
Status
{
Success
,
FrameFinished
,
EndOfFile
,
ReadError
,
DecodeError
,
RestartRequired
};
MediaDecoder
();
MediaDecoder
(
MediaObserver
observer
);
MediaDecoder
(
const
std
::
shared_ptr
<
MediaDemuxer
>&
demuxer
,
int
index
);
MediaDecoder
(
const
std
::
shared_ptr
<
MediaDemuxer
>&
demuxer
,
AVMediaType
type
)
:
MediaDecoder
(
demuxer
,
demuxer
->
selectStream
(
type
))
{}
~
MediaDecoder
();
void
emulateRate
()
{
emulateRate_
=
true
;
}
int
openInput
(
const
DeviceParams
&
);
void
setInterruptCallback
(
int
(
*
cb
)(
void
*
),
void
*
opaque
);
void
setIOContext
(
MediaIOHandle
*
ioctx
);
int
setup
(
AVMediaType
type
);
int
setupAudio
()
{
return
setup
(
AVMEDIA_TYPE_AUDIO
);
}
int
setupVideo
()
{
return
setup
(
AVMEDIA_TYPE_VIDEO
);
}
MediaDemuxer
::
Status
decode
();
Status
flush
();
int
getWidth
()
const
;
int
getHeight
()
const
;
std
::
string
getDecoderName
()
const
;
rational
<
double
>
getFps
()
const
;
AVPixelFormat
getPixelFormat
()
const
;
void
setOptions
(
const
std
::
map
<
std
::
string
,
std
::
string
>&
options
);
#ifdef RING_ACCEL
namespace
video
{
class
HardwareAccel
;
}
void
enableAccel
(
bool
enableAccel
);
#endif
class
MediaDecoder
{
public:
enum
class
Status
{
Success
,
FrameFinished
,
EOFError
,
ReadError
,
DecodeError
,
RestartRequired
};
MediaDecoder
();
~
MediaDecoder
();
void
emulateRate
()
{
emulateRate_
=
true
;
}
void
setInterruptCallback
(
int
(
*
cb
)(
void
*
),
void
*
opaque
);
int
openInput
(
const
DeviceParams
&
);
void
setIOContext
(
MediaIOHandle
*
ioctx
);
#ifdef ENABLE_VIDEO
int
setupFromVideoData
();
Status
decode
(
VideoFrame
&
);
Status
flush
(
VideoFrame
&
);
#endif // ENABLE_VIDEO
int
setupFromAudioData
();
Status
decode
(
AudioFrame
&
);
int
getWidth
()
const
;
int
getHeight
()
const
;
std
::
string
getDecoderName
()
const
;
MediaStream
getStream
(
std
::
string
name
=
""
)
const
;
rational
<
double
>
getFps
()
const
;
AVPixelFormat
getPixelFormat
()
const
;
void
setOptions
(
const
std
::
map
<
std
::
string
,
std
::
string
>&
options
);
#ifdef RING_ACCEL
void
enableAccel
(
bool
enableAccel
);
#endif
private:
NON_COPYABLE
(
MediaDecoder
);
MediaStream
getStream
(
std
::
string
name
=
""
)
const
;
Status
decode
(
AVPacket
&
)
;
private:
NON_COPYABLE
(
MediaDecoder
);
rational
<
unsigned
>
getTimeBase
()
const
;
rational
<
unsigned
>
getTimeBase
()
const
;
std
::
shared_ptr
<
MediaDemuxer
>
demuxer_
;
AVCodec
*
inputDecoder_
=
nullptr
;
AVCodecContext
*
decoderCtx_
=
nullptr
;
AVFormatContext
*
inputCtx_
=
nullptr
;
AVStream
*
avStream_
=
nullptr
;
int
streamIndex_
=
-
1
;
bool
emulateRate_
=
false
;
int64_t
startTime_
;
int64_t
lastTimestamp_
{
0
};
AVCodec
*
inputDecoder_
=
nullptr
;
AVCodecContext
*
decoderCtx_
=
nullptr
;
AVStream
*
avStream_
=
nullptr
;
bool
emulateRate_
=
false
;
int64_t
startTime_
;
int64_t
lastTimestamp_
;
DeviceParams
inputParams_
;
DeviceParams
inputParams_
;
int
correctPixFmt
(
int
input_pix_fmt
);
int
setupStream
(
AVMediaType
mediaType
);
int
selectStream
(
AVMediaType
type
);
int
correctPixFmt
(
int
input_pix_fmt
);
int
setupStream
();
bool
fallback_
=
false
;
bool
fallback_
=
false
;
#ifdef RING_ACCEL
bool
enableAccel_
=
true
;
std
::
unique_ptr
<
video
::
HardwareAccel
>
accel_
;
unsigned
short
accelFailures_
=
0
;
bool
enableAccel_
=
true
;
std
::
unique_ptr
<
video
::
HardwareAccel
>
accel_
;
unsigned
short
accelFailures_
=
0
;
#endif
MediaObserver
callback_
;
protected:
AVDictionary
*
options_
=
nullptr
;
protected:
AVDictionary
*
options_
=
nullptr
;
};
}
// namespace jami
src/media/video/video_base.cpp
View file @
693c8725
...
...
@@ -47,6 +47,14 @@ VideoGenerator::publishFrame()
notify
(
std
::
static_pointer_cast
<
MediaFrame
>
(
lastFrame_
));
}
void
VideoGenerator
::
publishFrame
(
std
::
shared_ptr
<
VideoFrame
>
frame
)
{
std
::
lock_guard
<
std
::
mutex
>
lk
(
mutex_
);
lastFrame_
=
std
::
move
(
frame
);
notify
(
std
::
static_pointer_cast
<
MediaFrame
>
(
lastFrame_
));
}
void
VideoGenerator
::
flushFrames
()
{
...
...
src/media/video/video_base.h
View file @
693c8725
...
...
@@ -80,6 +80,7 @@ public:
// getNewFrame and publishFrame must be called by the same thread only
VideoFrame
&
getNewFrame
();
void
publishFrame
();
void
publishFrame
(
std
::
shared_ptr
<
VideoFrame
>
);
void
flushFrames
();
private:
...
...
src/media/video/video_input.cpp
View file @
693c8725
...
...
@@ -228,40 +228,18 @@ VideoInput::isCapturing() const noexcept
bool
VideoInput
::
captureFrame
()
{
// Return true if capture could continue, false if must be stop
if
(
not
decoder_
)
return
false
;
auto
&
frame
=
getNewFrame
();
const
auto
ret
=
decoder_
->
decode
(
frame
);
switch
(
ret
)
{
case
MediaDecoder
:
:
Status
::
ReadError
:
return
false
;
// try to keep decoding
case
MediaDecoder
:
:
Status
::
DecodeError
:
return
true
;
case
MediaDecoder
:
:
Status
::
RestartRequired
:
createDecoder
();
#ifdef RING_ACCEL
JAMI_WARN
(
"Disabling hardware decoding due to previous failure"
);
decoder_
->
enableAccel
(
false
);
#endif
return
static_cast
<
bool
>
(
decoder_
);
// End of streamed file
case
MediaDecoder
:
:
Status
::
EOFError
:
createDecoder
();
return
static_cast
<
bool
>
(
decoder_
);
case
MediaDecoder
:
:
Status
::
FrameFinished
:
publishFrame
();
return
true
;
// continue decoding
case
MediaDecoder
:
:
Status
::
Success
:
default:
return
true
;
switch
(
decoder_
->
decode
())
{
case
MediaDemuxer
:
:
Status
::
EndOfFile
:
createDecoder
();
return
static_cast
<
bool
>
(
decoder_
);
case
MediaDemuxer
:
:
Status
::
ReadError
:
JAMI_ERR
()
<<
"Failed to decode frame"
;
return
false
;
default:
return
true
;
}
}
...
...
@@ -363,7 +341,9 @@ VideoInput::createDecoder()
return
;
}
auto
decoder
=
std
::
unique_ptr
<
MediaDecoder
>
(
new
MediaDecoder
());
auto
decoder
=
std
::
make_unique
<
MediaDecoder
>
([
this
](
const
std
::
shared_ptr
<
MediaFrame
>&
frame
)
mutable
{
publishFrame
(
std
::
static_pointer_cast
<
VideoFrame
>
(
frame
));
});
if
(
emulateRate_
)
decoder
->
emulateRate
();
...
...
@@ -379,7 +359,7 @@ VideoInput::createDecoder()
}
/* Data available, finish the decoding */
if
(
decoder
->
setup
FromVideoData
()
<
0
)
{
if
(
decoder
->
setup
Video
()
<
0
)
{
JAMI_ERR
(
"decoder IO startup failed"
);
foundDecOpts
(
decOpts_
);
return
;
...
...
@@ -521,7 +501,7 @@ VideoInput::initFile(std::string path)
DeviceParams
p
;
p
.
input
=
path
;
auto
dec
=
std
::
make_unique
<
MediaDecoder
>
();
if
(
dec
->
openInput
(
p
)
<
0
||
dec
->
setup
FromVideoData
()
<
0
)
{
if
(
dec
->
openInput
(
p
)
<
0
||
dec
->
setup
Video
()
<
0
)
{
return
initCamera
(
jami
::
getVideoDeviceMonitor
().
getDefaultDevice
());
}
...
...
src/media/video/video_receive_thread.cpp
View file @
693c8725
...
...
@@ -55,9 +55,9 @@ VideoReceiveThread::VideoReceiveThread(const std::string& id,
,
sink_
{
Manager
::
instance
().
createSinkClient
(
id
)}
,
mtu_
(
mtu
)
,
rotation_
(
0
)
,
requestKeyFrameCallback_
(
0
)
,
requestKeyFrameCallback_
()
,
loop_
(
std
::
bind
(
&
VideoReceiveThread
::
setup
,
this
),
std
::
bind
(
&
VideoReceiveThread
::
process
,
this
),
std
::
bind
(
&
VideoReceiveThread
::
decodeFrame
,
this
),
std
::
bind
(
&
VideoReceiveThread
::
cleanup
,
this
))
{}
...
...
@@ -76,7 +76,11 @@ VideoReceiveThread::startLoop()
// main thread to block while this executes, so it happens in the video thread.
bool
VideoReceiveThread
::
setup
()
{
videoDecoder_
.
reset
(
new
MediaDecoder
());
videoDecoder_
.
reset
(
new
MediaDecoder
([
this
](
const
std
::
shared_ptr
<
MediaFrame
>&
frame
)
mutable
{
if
(
auto
displayMatrix
=
displayMatrix_
)
av_frame_new_side_data_from_buf
(
frame
->
pointer
(),
AV_FRAME_DATA_DISPLAYMATRIX
,
av_buffer_ref
(
displayMatrix
.
get
()));
publishFrame
(
std
::
static_pointer_cast
<
VideoFrame
>
(
frame
));
}));
dstWidth_
=
args_
.
width
;
dstHeight_
=
args_
.
height
;
...
...
@@ -120,7 +124,7 @@ bool VideoReceiveThread::setup()
if
(
requestKeyFrameCallback_
)
requestKeyFrameCallback_
();
if
(
videoDecoder_
->
setup
FromVideoData
())
{
if
(
videoDecoder_
->
setup
Video
())
{
JAMI_ERR
(
"decoder IO startup failed"
);
return
false
;
}
...
...
@@ -149,9 +153,6 @@ bool VideoReceiveThread::setup()
return
true
;
}
void
VideoReceiveThread
::
process
()
{
decodeFrame
();
}
void
VideoReceiveThread
::
cleanup
()
{
detach
(
sink_
.
get
());
...
...
@@ -185,53 +186,15 @@ void VideoReceiveThread::addIOContext(SocketPair& socketPair)
demuxContext_
.
reset
(
socketPair
.
createIOContext
(
mtu_
));
}
bool
VideoReceiveThread
::
decodeFrame
()
void
VideoReceiveThread
::
decodeFrame
()
{
auto
&
frame
=
getNewFrame
();
const
auto
ret
=
videoDecoder_
->
decode
(
frame
);
if
(
auto
displayMatrix
=
displayMatrix_
)
av_frame_new_side_data_from_buf
(
frame
.
pointer
(),
AV_FRAME_DATA_DISPLAYMATRIX
,
av_buffer_ref
(
displayMatrix
.
get
()));
switch
(
ret
)
{
case
MediaDecoder
:
:
Status
::
FrameFinished
:
publishFrame
();
return
true
;
case
MediaDecoder
:
:
Status
::
DecodeError
:
JAMI_WARN
(
"video decoding failure"
);
if
(
requestKeyFrameCallback_
)
{
auto
keyFrameCheckTimer
=
std
::
chrono
::
steady_clock
::
now
()
-
lastKeyFrameTime_
;
if
(
keyFrameCheckTimer
>=
MS_BETWEEN_2_KEYFRAME_REQUEST
)
{
lastKeyFrameTime_
=
std
::
chrono
::
steady_clock
::
now
();
requestKeyFrameCallback_
();
}
}
break
;
case
MediaDecoder
:
:
Status
::
ReadError
:
JAMI_ERR
(
"fatal error, read failed"
);
loop_
.
stop
();
break
;
case
MediaDecoder
:
:
Status
::
RestartRequired
:
// disable accel, reset decoder's AVCodecContext
#ifdef RING_ACCEL
videoDecoder_
->
enableAccel
(
false
);
#endif
videoDecoder_
->
setupFromVideoData
();
break
;
case
MediaDecoder
:
:
Status
::
Success
:
case
MediaDecoder
:
:
Status
::
EOFError
:
break
;
auto
status
=
videoDecoder_
->
decode
();
if
(
status
==
MediaDemuxer
::
Status
::
EndOfFile
||
status
==
MediaDemuxer
::
Status
::
ReadError
)
{
loop_
.
stop
();
}
return
false
;
}
void
VideoReceiveThread
::
enterConference
()
{
if
(
!
loop_
.
isRunning
())
...
...
src/media/video/video_receive_thread.h
View file @
693c8725
...
...
@@ -94,7 +94,7 @@ private:
std
::
function
<
void
(
void
)
>
requestKeyFrameCallback_
;
void
openDecoder
();
bool
decodeFrame
();
void
decodeFrame
();
static
int
interruptCb
(
void
*
ctx
);
static
int
readFunction
(
void
*
opaque
,
uint8_t
*
buf
,
int
buf_size
);
...
...
src/observer.h
View file @
693c8725
...
...
@@ -28,6 +28,7 @@
#include <memory>
#include <set>
#include <mutex>
#include <functional>
#include <ciso646> // fix windows compiler bug
namespace
jami
{
...
...
@@ -42,6 +43,7 @@ class Observable
{
public:
Observable
()
:
mutex_
(),
observers_
()
{}
virtual
~
Observable
()
{
std
::
lock_guard
<
std
::
mutex
>
lk
(
mutex_
);
for
(
auto
&
o
:
observers_
)
...
...
@@ -97,4 +99,17 @@ public:
virtual
void
detached
(
Observable
<
T
>*
)
{};
};
template
<
typename
T
>
class
FuncObserver
:
public
Observer
<
T
>
{
public:
using
F
=
std
::
function
<
void
(
const
T
&
)
>
;
FuncObserver
(
F
f
)
:
f_
(
f
)
{};
virtual
~
FuncObserver
()
{};
void
update
(
Observable
<
T
>*
,
const
T
&
t
)
override
{
f_
(
t
);
}
private:
F
f_
;
};
};
// namespace jami
test/unitTest/media/test_media_decoder.cpp
View file @
693c8725
...
...
@@ -61,7 +61,6 @@ MediaDecoderTest::setUp()
{
DRing
::
init
(
DRing
::
InitFlag
(
DRing
::
DRING_FLAG_DEBUG
|
DRing
::
DRING_FLAG_CONSOLE_LOG
));
libav_utils
::
ring_avcodec_init
();
decoder_
.
reset
(
new
MediaDecoder
);
}
void
...
...
@@ -80,28 +79,26 @@ MediaDecoderTest::testAudioFile()
writeWav
();
decoder_
.
reset
(
new
MediaDecoder
([
this
](
const
std
::
shared_ptr
<
MediaFrame
>&&
f
)
mutable
{
CPPUNIT_ASSERT
(
f
->
pointer
()
->
sample_rate
==
decoder_
->
getStream
().
sampleRate
);
CPPUNIT_ASSERT
(
f
->
pointer
()
->
channels
==
decoder_
->
getStream
().
nbChannels
);
}));
DeviceParams
dev
;
dev
.
input
=
filename_
;
CPPUNIT_ASSERT
(
decoder_
->
openInput
(
dev
)
>=
0
);
CPPUNIT_ASSERT
(
decoder_
->
setup
FromAudioData
()
>=
0
);
CPPUNIT_ASSERT
(
decoder_
->
setup
Audio
()
>=
0
);
bool
done
=
false
;
while
(
!
done
)
{
AudioFrame
frame
;
switch
(
decoder_
->
decode
(
frame
))
{
case
MediaDecoder
:
:
Status
::
FrameFinished
:
CPPUNIT_ASSERT
(
frame
.
pointer
()
->
sample_rate
==
decoder_
->
getStream
().
sampleRate
);
CPPUNIT_ASSERT
(
frame
.
pointer
()
->
channels
==
decoder_
->
getStream
().
nbChannels
);
break
;
case
MediaDecoder
:
:
Status
::
DecodeError
:
case
MediaDecoder
:
:
Status
::
ReadError
:
switch
(
decoder_
->
decode
())
{
case
MediaDemuxer
:
:
Status
::
ReadError
:
CPPUNIT_ASSERT_MESSAGE
(
"Decode error"
,
false
);
done
=
true
;
break
;
case
MediaDe
coder
:
:
Status
::
EOFError
:
case
MediaDe
muxer
:
:
Status
::
EndOfFile
:
done
=
true
;
break
;
case
MediaDe
cod
er
:
:
Status
::
Success
:
case
MediaDe
mux
er
:
:
Status
::
Success
:
default:
break
;
}
...
...
Write
Preview