Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
J
jami-daemon
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
130
Issues
130
List
Boards
Labels
Service Desk
Milestones
Iterations
Requirements
Requirements
List
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Operations
Operations
Incidents
Analytics
Analytics
Insights
Issue
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
savoirfairelinux
jami-daemon
Commits
880c285a
Commit
880c285a
authored
Jul 16, 2019
by
Adrien Béraud
1
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
media: split demuxer and decoder
Change-Id: Id8d3bc885798850e00ef21d11e7f8276b54cc9be
parent
59cc453c
Changes
14
Hide whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
343 additions
and
391 deletions
+343
-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
+134
-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 @
880c285a
...
...
@@ -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 @
880c285a
...
...
@@ -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 @
880c285a
...
...
@@ -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 @
880c285a
...
...
@@ -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 @
880c285a
...
...
@@ -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 @
880c285a
...
...
@@ -3,6 +3,7 @@
*
* Author: Guillaume Roguez <Guillaume.Roguez@savoirfairelinux.com>
* Author: Philippe Gorley <philippe.gorley@savoirfairelinux.com>
* Author: Adrien Béraud <adrien.beraud@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
...
...
@@ -53,23 +54,20 @@ const constexpr auto jitterBufferMaxDelay_ = std::chrono::milliseconds(50);
// maximum number of times accelerated decoding can fail in a row before falling back to software
const
constexpr
unsigned
MAX_ACCEL_FAILURES
{
5
};
MediaDe
coder
::
MediaDecod
er
()
:
MediaDe
muxer
::
MediaDemux
er
()
:
inputCtx_
(
avformat_alloc_context
()),
startTime_
(
AV_NOPTS_VALUE
)
{
}
{}
MediaDe
coder
::~
MediaDecod
er
()
MediaDe
muxer
::~
MediaDemux
er
()
{
if
(
decoderCtx_
)
avcodec_free_context
(
&
decoderCtx_
);
if
(
inputCtx_
)
avformat_close_input
(
&
inputCtx_
);
av_dict_free
(
&
options_
);
}
int
MediaDecoder
::
openInput
(
const
DeviceParams
&
params
)
int
MediaDemuxer
::
openInput
(
const
DeviceParams
&
params
)
{
inputParams_
=
params
;
AVInputFormat
*
iformat
=
av_find_input_format
(
params
.
format
.
c_str
());
...
...
@@ -123,12 +121,6 @@ int MediaDecoder::openInput(const DeviceParams& params)
JAMI_DBG
(
"Trying to open device %s with format %s, pixel format %s, size %dx%d, rate %lf"
,
params
.
input
.
c_str
(),
params
.
format
.
c_str
(),
params
.
pixel_format
.
c_str
(),
params
.
width
,
params
.
height
,
params
.
framerate
.
real
());
#ifdef RING_ACCEL
// if there was a fallback to software decoding, do not enable accel
// it has been disabled already by the video_receive_thread/video_input
enableAccel_
&=
Manager
::
instance
().
videoPreferences
.
getDecodingAccelerated
();
#endif
int
ret
=
avformat_open_input
(
&
inputCtx_
,
params
.
input
.
c_str
(),
...
...
@@ -144,7 +136,26 @@ int MediaDecoder::openInput(const DeviceParams& params)
return
ret
;
}
void
MediaDecoder
::
setInterruptCallback
(
int
(
*
cb
)(
void
*
),
void
*
opaque
)
void
MediaDemuxer
::
findStreamInfo
()
{
if
(
not
streamInfoFound_
)
{
inputCtx_
->
max_analyze_duration
=
30
*
AV_TIME_BASE
;
int
err
;
if
((
err
=
avformat_find_stream_info
(
inputCtx_
,
nullptr
))
<
0
)
{
JAMI_ERR
()
<<
"Could not find stream info: "
<<
libav_utils
::
getError
(
err
);
}
streamInfoFound_
=
true
;
}
}
int
MediaDemuxer
::
selectStream
(
AVMediaType
type
)
{
return
av_find_best_stream
(
inputCtx_
,
type
,
-
1
,
-
1
,
nullptr
,
0
);
}
void
MediaDemuxer
::
setInterruptCallback
(
int
(
*
cb
)(
void
*
),
void
*
opaque
)
{
if
(
cb
)
{
inputCtx_
->
interrupt_callback
.
callback
=
cb
;
...
...
@@ -154,48 +165,104 @@ void MediaDecoder::setInterruptCallback(int (*cb)(void*), void *opaque)
}
}
void
MediaDe
cod
er
::
setIOContext
(
MediaIOHandle
*
ioctx
)
void
MediaDe
mux
er
::
setIOContext
(
MediaIOHandle
*
ioctx
)
{
inputCtx_
->
pb
=
ioctx
->
getContext
();
}
int
MediaDecoder
::
setupFromAudioData
()
MediaDemuxer
::
Status
MediaDemuxer
::
decode
()
{
return
setupStream
(
AVMEDIA_TYPE_AUDIO
);
auto
packet
=
std
::
unique_ptr
<
AVPacket
,
std
::
function
<
void
(
AVPacket
*
)
>>
(
av_packet_alloc
(),
[](
AVPacket
*
p
){
if
(
p
)
av_packet_free
(
&
p
);
});
int
ret
=
av_read_frame
(
inputCtx_
,
packet
.
get
());
if
(
ret
==
AVERROR
(
EAGAIN
))
{
return
Status
::
Success
;
}
else
if
(
ret
==
AVERROR_EOF
)
{
return
Status
::
EndOfFile
;
}
else
if
(
ret
<
0
)
{
JAMI_ERR
(
"Couldn't read frame: %s
\n
"
,
libav_utils
::
getError
(
ret
).
c_str
());
return
Status
::
ReadError
;
}
auto
streamIndex
=
packet
->
stream_index
;
if
(
static_cast
<
unsigned
>
(
streamIndex
)
>=
streams_
.
size
()
||
streamIndex
<
0
)
{
return
Status
::
Success
;
}
auto
&
cb
=
streams_
[
streamIndex
];
if
(
cb
)
cb
(
*
packet
.
get
());
return
Status
::
Success
;
}
int
MediaDecoder
::
selectStream
(
AVMediaType
type
)
MediaDecoder
::
MediaDecoder
(
const
std
::
shared_ptr
<
MediaDemuxer
>&
demuxer
,
int
index
)
:
demuxer_
(
demuxer
),
avStream_
(
demuxer
->
getStream
(
index
))
{
return
av_find_best_stream
(
inputCtx_
,
type
,
-
1
,
-
1
,
&
inputDecoder_
,
0
);
demuxer
->
setStreamCallback
(
index
,
[
this
](
AVPacket
&
packet
)
{
decode
(
packet
);
});
setupStream
();
}
MediaDecoder
::
MediaDecoder
()
:
demuxer_
(
new
MediaDemuxer
)
{}
MediaDecoder
::
MediaDecoder
(
MediaObserver
o
)
:
demuxer_
(
new
MediaDemuxer
),
callback_
(
std
::
move
(
o
))
{}
MediaDecoder
::~
MediaDecoder
()
{
#ifdef RING_ACCEL
if
(
decoderCtx_
&&
decoderCtx_
->
hw_device_ctx
)
av_buffer_unref
(
&
decoderCtx_
->
hw_device_ctx
);
#endif
if
(
decoderCtx_
)
avcodec_free_context
(
&
decoderCtx_
);
}
int
MediaDecoder
::
setupStream
(
AVMediaType
mediaType
)
MediaDecoder
::
openInput
(
const
DeviceParams
&
p
)
{
int
ret
=
0
;
std
::
string
streamType
=
av_get_media_type_string
(
mediaType
);
return
demuxer_
->
openInput
(
p
)
;
}
avcodec_free_context
(
&
decoderCtx_
);
void
MediaDecoder
::
setInterruptCallback
(
int
(
*
cb
)(
void
*
),
void
*
opaque
)
{
demuxer_
->
setInterruptCallback
(
cb
,
opaque
);
}
// Increase analyze time to solve synchronization issues between callers.
static
const
unsigned
MAX_ANALYZE_DURATION
=
30
;
inputCtx_
->
max_analyze_duration
=
MAX_ANALYZE_DURATION
*
AV_TIME_BASE
;
// If fallback from accel, don't check for stream info, it's already done
if
(
!
fallback_
)
{
JAMI_DBG
()
<<
"Finding "
<<
streamType
<<
" stream info"
;
if
((
ret
=
avformat_find_stream_info
(
inputCtx_
,
nullptr
))
<
0
)
{
// Always fail here
JAMI_ERR
()
<<
"Could not find "
<<
streamType
<<
" stream info: "
<<
libav_utils
::
getError
(
ret
);
return
-
1
;
}
}
void
MediaDecoder
::
setIOContext
(
MediaIOHandle
*
ioctx
)
{
demuxer_
->
setIOContext
(
ioctx
);
}
if
((
streamIndex_
=
selectStream
(
mediaType
))
<
0
)
{
JAMI_ERR
()
<<
"No suitable "
<<
streamType
<<
" stream found"
;
int
MediaDecoder
::
setup
(
AVMediaType
type
)
{
demuxer_
->
findStreamInfo
();
auto
stream
=
demuxer_
->
selectStream
(
type
);
if
(
stream
<
0
)
return
-
1
;
}
avStream_
=
demuxer_
->
getStream
(
stream
);
demuxer_
->
setStreamCallback
(
stream
,
[
this
](
AVPacket
&
packet
)
{
decode
(
packet
);
});
return
setupStream
();
}
int
MediaDecoder
::
setupStream
()
{
int
ret
=
0
;
avcodec_free_context
(
&
decoderCtx_
);
avStream_
=
inputCtx_
->
streams
[
streamIndex_
];
inputDecoder_
=
findDecoder
(
avStream_
->
codecpar
->
codec_id
);
if
(
!
inputDecoder_
)
{
JAMI_ERR
()
<<
"Unsupported codec"
;
...
...
@@ -209,23 +276,15 @@ MediaDecoder::setupStream(AVMediaType mediaType)
}
avcodec_parameters_to_context
(
decoderCtx_
,
avStream_
->
codecpar
);
decoderCtx_
->
framerate
=
avStream_
->
avg_frame_rate
;
if
(
mediaT
ype
==
AVMEDIA_TYPE_VIDEO
)
{
if
(
avStream_
->
codecpar
->
codec_t
ype
==
AVMEDIA_TYPE_VIDEO
)
{
if
(
decoderCtx_
->
framerate
.
num
==
0
||
decoderCtx_
->
framerate
.
den
==
0
)
decoderCtx_
->
framerate
=
inputParams_
.
framerate
;
if
(
decoderCtx_
->
framerate
.
num
==
0
||
decoderCtx_
->
framerate
.
den
==
0
)
decoderCtx_
->
framerate
=
av_inv_q
(
decoderCtx_
->
time_base
);
if
(
decoderCtx_
->
framerate
.
num
==
0
||
decoderCtx_
->
framerate
.
den
==
0
)
decoderCtx_
->
framerate
=
{
30
,
1
};
}
decoderCtx_
->
thread_count
=
std
::
max
(
1u
,
std
::
min
(
8u
,
std
::
thread
::
hardware_concurrency
()
/
2
));
if
(
emulateRate_
)
JAMI_DBG
()
<<
"Using framerate emulation"
;
startTime_
=
av_gettime
();
// used to set pts after decoding, and for rate emulation
#ifdef RING_ACCEL
if
(
mediaType
==
AVMEDIA_TYPE_VIDEO
)
{
if
(
enableAccel_
)
{
accel_
=
video
::
HardwareAccel
::
setupDecoder
(
decoderCtx_
->
codec_id
,
decoderCtx_
->
width
,
decoderCtx_
->
height
);
...
...
@@ -238,10 +297,16 @@ MediaDecoder::setupStream(AVMediaType mediaType)
}
else
{
JAMI_WARN
()
<<
"Hardware decoding disabled by user preference"
;
}
}
#endif
}
JAMI_DBG
()
<<
"Decoding "
<<
streamType
<<
" using "
<<
inputDecoder_
->
long_name
<<
" ("
<<
inputDecoder_
->
name
<<
")"
;
decoderCtx_
->
thread_count
=
std
::
max
(
1u
,
std
::
min
(
8u
,
std
::
thread
::
hardware_concurrency
()
/
2
));
if
(
emulateRate_
)
JAMI_DBG
()
<<
"Using framerate emulation"
;
startTime_
=
av_gettime
();
// used to set pts after decoding, and for rate emulation
JAMI_DBG
()
<<
"Decoding using "
<<
inputDecoder_
->
long_name
<<
" ("
<<
inputDecoder_
->
name
<<
")"
;
decoderCtx_
->
err_recognition
=
(
AV_EF_CRCCHECK
|
AV_EF_BITSTREAM
|
AV_EF_BUFFER
|
AV_EF_EXPLODE
|
AV_EF_CAREFUL
|
AV_EF_COMPLIANT
|
AV_EF_AGGRESSIVE
);
ret
=
avcodec_open2
(
decoderCtx_
,
inputDecoder_
,
nullptr
);
if
(
ret
<
0
)
{
...
...
@@ -252,39 +317,17 @@ MediaDecoder::setupStream(AVMediaType mediaType)
return
0
;
}
#ifdef ENABLE_VIDEO
int
MediaDecoder
::
setupFromVideoData
()
{
return
setupStream
(
AVMEDIA_TYPE_VIDEO
);
}
MediaDecoder
::
Status
MediaDecoder
::
decode
(
VideoFrame
&
resul
t
)
MediaDecoder
::
decode
(
AVPacket
&
packe
t
)
{
AVPacket
inpacket
;
av_init_packet
(
&
inpacket
);
int
ret
=
av_read_frame
(
inputCtx_
,
&
inpacket
);
if
(
ret
==
AVERROR
(
EAGAIN
))
{
return
Status
::
Success
;
}
else
if
(
ret
==
AVERROR_EOF
)
{
return
Status
::
EOFError
;
}
else
if
(
ret
<
0
)
{
JAMI_ERR
(
"Couldn't read frame: %s
\n
"
,
libav_utils
::
getError
(
ret
).
c_str
());
return
Status
::
ReadError
;
}
// is this a packet from the video stream?
if
(
inpacket
.
stream_index
!=
streamIndex_
)
{
av_packet_unref
(
&
inpacket
);
return
Status
::
Success
;
}
auto
frame
=
result
.
pointer
();
int
frameFinished
=
0
;
ret
=
avcodec_send_packet
(
decoderCtx_
,
&
in
packet
);
auto
ret
=
avcodec_send_packet
(
decoderCtx_
,
&
packet
);
if
(
ret
<
0
&&
ret
!=
AVERROR
(
EAGAIN
))
{
return
ret
==
AVERROR_EOF
?
Status
::
Success
:
Status
::
DecodeError
;
}
auto
f
=
std
::
make_shared
<
MediaFrame
>
();
auto
frame
=
f
->
pointer
();
ret
=
avcodec_receive_frame
(
decoderCtx_
,
frame
);
if
(
ret
<
0
&&
ret
!=
AVERROR
(
EAGAIN
)
&&
ret
!=
AVERROR_EOF
)
{
return
Status
::
DecodeError
;
...
...
@@ -292,8 +335,6 @@ MediaDecoder::decode(VideoFrame& result)
if
(
ret
>=
0
)
frameFinished
=
1
;
av_packet_unref
(
&
inpacket
);
if
(
frameFinished
)
{
frame
->
format
=
(
AVPixelFormat
)
correctPixFmt
(
frame
->
format
);
auto
packetTimestamp
=
frame
->
pts
;
// in stream time base
...
...
@@ -310,73 +351,18 @@ MediaDecoder::decode(VideoFrame& result)
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
microseconds
(
target
-
now
));
}
}
if
(
callback_
)
callback_
(
std
::
move
(
f
));
return
Status
::
FrameFinished
;
}
return
Status
::
Success
;
}
#endif // ENABLE_VIDEO
MediaDe
cod
er
::
Status
MediaDecoder
::
decode
(
AudioFrame
&
decodedFrame
)
MediaDe
mux
er
::
Status
MediaDecoder
::
decode
()
{
const
auto
frame
=
decodedFrame
.
pointer
();
AVPacket
inpacket
;
av_init_packet
(
&
inpacket
);
int
ret
=
av_read_frame
(
inputCtx_
,
&
inpacket
);
if
(
ret
==
AVERROR
(
EAGAIN
))
{
return
Status
::
Success
;
}
else
if
(
ret
==
AVERROR_EOF
)
{
return
Status
::
EOFError
;
}
else
if
(
ret
<
0
)
{
JAMI_ERR
(
"Couldn't read frame: %s
\n
"
,
libav_utils
::
getError
(
ret
).
c_str
());
return
Status
::
ReadError
;
}
// is this a packet from the audio stream?
if
(
inpacket
.
stream_index
!=
streamIndex_
)
{
av_packet_unref
(
&
inpacket
);
return
Status
::
Success
;
}
int
frameFinished
=
0
;
ret
=
avcodec_send_packet
(
decoderCtx_
,
&
inpacket
);
if
(
ret
<
0
&&
ret
!=
AVERROR
(
EAGAIN
))
return
ret
==
AVERROR_EOF
?
Status
::
Success
:
Status
::
DecodeError
;
ret
=
avcodec_receive_frame
(
decoderCtx_
,
frame
);
if
(
ret
<
0
&&
ret
!=
AVERROR
(
EAGAIN
)
&&
ret
!=
AVERROR_EOF
)
return
Status
::
DecodeError
;
if
(
ret
>=
0
)
frameFinished
=
1
;
if
(
frameFinished
)
{
av_packet_unref
(
&
inpacket
);
// channel layout is needed if frame will be resampled
if
(
!
frame
->
channel_layout
)
frame
->
channel_layout
=
av_get_default_channel_layout
(
frame
->
channels
);
auto
packetTimestamp
=
frame
->
pts
;
// NOTE don't use clock to rescale audio pts, it may create artifacts
frame
->
pts
=
av_rescale_q_rnd
(
frame
->
pts
,
avStream_
->
time_base
,
decoderCtx_
->
time_base
,
static_cast
<
AVRounding
>
(
AV_ROUND_NEAR_INF
|
AV_ROUND_PASS_MINMAX
));
lastTimestamp_
=
frame
->
pts
;
if
(
emulateRate_
and
packetTimestamp
!=
AV_NOPTS_VALUE
)
{
auto
frame_time
=
getTimeBase
()
*
(
packetTimestamp
-
avStream_
->
start_time
);
auto
target
=
startTime_
+
static_cast
<
std
::
int64_t
>
(
frame_time
.
real
()
*
1e6
);
auto
now
=
av_gettime
();
if
(
target
>
now
)
{
std
::
this_thread
::
sleep_for
(
std
::
chrono
::
microseconds
(
target
-
now
));
}
}
return
Status
::
FrameFinished
;
}
return
Status
::
Success
;
return
demuxer_
->
decode
();
}
#ifdef ENABLE_VIDEO
...
...
@@ -395,7 +381,7 @@ MediaDecoder::enableAccel(bool enableAccel)
#endif
MediaDecoder
::
Status
MediaDecoder
::
flush
(
VideoFrame
&
result
)
MediaDecoder
::
flush
()
{
AVPacket
inpacket
;
av_init_packet
(
&
inpacket
);
...
...
@@ -406,7 +392,8 @@ MediaDecoder::flush(VideoFrame& result)
if
(
ret
<
0
&&
ret
!=
AVERROR
(
EAGAIN
))
return
ret
==
AVERROR_EOF
?
Status
::
Success
:
Status
::
DecodeError
;
ret
=
avcodec_receive_frame
(
decoderCtx_
,
result
.
pointer
());
auto
result
=
std
::
make_shared
<
MediaFrame
>
();
ret
=
avcodec_receive_frame
(
decoderCtx_
,
result
->
pointer
());
if
(
ret
<
0
&&
ret
!=
AVERROR
(
EAGAIN
)
&&
ret
!=
AVERROR_EOF
)
return
Status
::
DecodeError
;
if
(
ret
>=
0
)
...
...
@@ -414,7 +401,9 @@ MediaDecoder::flush(VideoFrame& result)
if
(
frameFinished
)
{
av_packet_unref
(
&
inpacket
);
return
Status
::
EOFError
;
if
(
callback_
)
callback_
(
std
::
move
(
result
));
return
Status
::
FrameFinished
;
}
return
Status
::
Success
;
...
...
src/media/media_decoder.h
View file @
880c285a
...
...
@@ -22,17 +22,22 @@
#include "config.h"
#include "rational.h"