Skip to content
项目
群组
代码片段
帮助
正在加载...
登录
切换导航
F
freeswitch
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
分枝图
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
分枝图
统计图
创建新议题
作业
提交
议题看板
打开侧边栏
张华
freeswitch
Commits
b29174e8
提交
b29174e8
authored
4月 23, 2015
作者:
Seven Du
提交者:
Michael Jerris
5月 28, 2015
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
FS-7503 FS-7519: refactor to support video playback using libavformat
need -lswscale to converto from non-I420 fmt to I420
上级
a8a2c32a
显示空白字符变更
内嵌
并排
正在显示
2 个修改的文件
包含
660 行增加
和
166 行删除
+660
-166
Makefile.sample
src/mod/formats/mod_avformat/Makefile.sample
+1
-1
mod_avformat.c
src/mod/formats/mod_avformat/mod_avformat.c
+659
-165
没有找到文件。
src/mod/formats/mod_avformat/Makefile.sample
浏览文件 @
b29174e8
LOCAL_LDFLAGS
=
-L
/opt/av/lib
-lavformat
-lavcodec
-lavutil
-lavresample
LOCAL_LDFLAGS
=
-L
/opt/av/lib
-lavformat
-lavcodec
-lavutil
-lavresample
-lswscale
LOCAL_CFLAGS
=
-I
/opt/av/include
LOCAL_LIBADD
=
...
...
src/mod/formats/mod_avformat/mod_avformat.c
浏览文件 @
b29174e8
...
...
@@ -38,6 +38,9 @@
#include <libavutil/channel_layout.h>
// #include <libavutil/timestamp.h>
#include <libavresample/avresample.h>
#include <libswscale/swscale.h>
#define SCALE_FLAGS SWS_BICUBIC
#define DFT_RECORD_OFFSET 350
SWITCH_MODULE_LOAD_FUNCTION
(
mod_avformat_load
);
...
...
@@ -69,27 +72,72 @@ static void __attribute__((unused)) fill_avframe(AVFrame *pict, switch_image_t *
}
}
static
void
__attribute__
((
unused
))
avframe2img
(
AVFrame
*
pict
,
switch_image_t
*
img
)
{
int
i
;
uint8_t
*
y
=
pict
->
data
[
0
];
uint8_t
*
u
=
pict
->
data
[
1
];
uint8_t
*
v
=
pict
->
data
[
2
];
/* Y */
for
(
i
=
0
;
i
<
img
->
d_h
;
i
++
)
{
memcpy
(
&
img
->
planes
[
0
][
i
*
img
->
stride
[
0
]],
y
+
i
*
pict
->
linesize
[
0
],
img
->
d_w
);
}
/* U/V */
for
(
i
=
0
;
i
<
pict
->
height
/
2
;
i
++
)
{
memcpy
(
&
img
->
planes
[
1
][
i
*
img
->
stride
[
1
]],
u
+
i
*
pict
->
linesize
[
1
],
img
->
d_w
/
2
);
memcpy
(
&
img
->
planes
[
2
][
i
*
img
->
stride
[
2
]],
v
+
i
*
pict
->
linesize
[
2
],
img
->
d_w
/
2
);
}
}
static
void
__attribute__
((
unused
))
avframe2fd
(
AVFrame
*
pict
,
int
fd
)
{
int
i
;
uint8_t
*
y
=
pict
->
data
[
0
];
uint8_t
*
u
=
pict
->
data
[
1
];
uint8_t
*
v
=
pict
->
data
[
2
];
/* Y */
for
(
i
=
0
;
i
<
pict
->
height
;
i
++
)
{
write
(
fd
,
y
+
i
*
pict
->
linesize
[
0
],
pict
->
width
);
}
/* U/V */
for
(
i
=
0
;
i
<
pict
->
height
/
2
;
i
++
)
{
write
(
fd
,
u
+
i
*
pict
->
linesize
[
1
],
pict
->
width
/
2
);
}
for
(
i
=
0
;
i
<
pict
->
height
/
2
;
i
++
)
{
write
(
fd
,
v
+
i
*
pict
->
linesize
[
2
],
pict
->
width
/
2
);
}
}
/* App interface */
// a wrapper around a single output AVStream
typedef
struct
Output
Stream
{
typedef
struct
Media
Stream
{
AVStream
*
st
;
AVFrame
*
frame
;
AVFrame
*
tmp_frame
;
int64_t
next_pts
;
struct
AVAudioResampleContext
*
resample_ctx
;
// audio
int
channels
;
int
sample_rate
;
struct
AVAudioResampleContext
*
resample_ctx
;
//video
int
width
;
int
height
;
}
OutputStream
;
struct
SwsContext
*
sws_ctx
;
int64_t
next_pts
;
}
MediaStream
;
typedef
struct
record_helper_s
{
switch_mutex_t
*
mutex
;
AVFormatContext
*
o
c
;
Output
Stream
*
video_st
;
AVFormatContext
*
f
c
;
Media
Stream
*
video_st
;
switch_timer_t
*
timer
;
int
in_callback
;
switch_queue_t
*
video_queue
;
...
...
@@ -172,7 +220,7 @@ static int write_frame(AVFormatContext *fmt_ctx, const AVRational *time_base, AV
}
/* Add an output stream. */
static
switch_status_t
add_stream
(
OutputStream
*
ost
,
AVFormatContext
*
o
c
,
AVCodec
**
codec
,
enum
AVCodecID
codec_id
,
switch_mm_t
*
mm
)
static
switch_status_t
add_stream
(
MediaStream
*
mst
,
AVFormatContext
*
f
c
,
AVCodec
**
codec
,
enum
AVCodecID
codec_id
,
switch_mm_t
*
mm
)
{
AVCodecContext
*
c
;
switch_status_t
status
=
SWITCH_STATUS_FALSE
;
...
...
@@ -186,14 +234,14 @@ static switch_status_t add_stream(OutputStream *ost, AVFormatContext *oc, AVCode
return
status
;
}
ost
->
st
=
avformat_new_stream
(
o
c
,
*
codec
);
if
(
!
o
st
->
st
)
{
mst
->
st
=
avformat_new_stream
(
f
c
,
*
codec
);
if
(
!
m
st
->
st
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not allocate stream
\n
"
);
return
status
;
}
ost
->
st
->
id
=
o
c
->
nb_streams
-
1
;
c
=
o
st
->
st
->
codec
;
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "id:%d den:%d num:%d\n",
ost->st->id, ost->st->time_base.den, o
st->st->time_base.num);
mst
->
st
->
id
=
f
c
->
nb_streams
-
1
;
c
=
m
st
->
st
->
codec
;
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "id:%d den:%d num:%d\n",
mst->st->id, mst->st->time_base.den, m
st->st->time_base.num);
if
(
threads
>
4
)
{
threads
=
4
;
...
...
@@ -203,8 +251,8 @@ static switch_status_t add_stream(OutputStream *ost, AVFormatContext *oc, AVCode
case
AVMEDIA_TYPE_AUDIO
:
c
->
sample_fmt
=
(
*
codec
)
->
sample_fmts
?
(
*
codec
)
->
sample_fmts
[
0
]
:
AV_SAMPLE_FMT_FLTP
;
c
->
bit_rate
=
128000
;
c
->
sample_rate
=
o
st
->
sample_rate
=
44100
;
c
->
channels
=
o
st
->
channels
;
c
->
sample_rate
=
m
st
->
sample_rate
=
44100
;
c
->
channels
=
m
st
->
channels
;
c
->
channel_layout
=
av_get_default_channel_layout
(
c
->
channels
);
if
(
mm
)
{
...
...
@@ -212,7 +260,7 @@ static switch_status_t add_stream(OutputStream *ost, AVFormatContext *oc, AVCode
c
->
bit_rate
=
mm
->
ab
*
1024
;
}
if
(
mm
->
samplerate
)
{
c
->
sample_rate
=
o
st
->
sample_rate
=
mm
->
samplerate
;
c
->
sample_rate
=
m
st
->
sample_rate
=
mm
->
samplerate
;
}
}
...
...
@@ -229,13 +277,13 @@ static switch_status_t add_stream(OutputStream *ost, AVFormatContext *oc, AVCode
c
->
codec_id
=
codec_id
;
c
->
bit_rate
=
1000000
;
/* Resolution must be a multiple of two. */
c
->
width
=
o
st
->
width
;
c
->
height
=
o
st
->
height
;
o
st
->
st
->
time_base
.
den
=
1000
;
o
st
->
st
->
time_base
.
num
=
1
;
c
->
width
=
m
st
->
width
;
c
->
height
=
m
st
->
height
;
m
st
->
st
->
time_base
.
den
=
1000
;
m
st
->
st
->
time_base
.
num
=
1
;
c
->
time_base
.
den
=
1000
;
c
->
time_base
.
num
=
1
;
c
->
gop_size
=
25
;
/* emit one intra frame every x frames at m
o
st */
c
->
gop_size
=
25
;
/* emit one intra frame every x frames at m
m
st */
c
->
pix_fmt
=
AV_PIX_FMT_YUV420P
;
c
->
thread_count
=
threads
;
c
->
rc_initial_buffer_occupancy
=
buffer_bytes
*
8
;
...
...
@@ -263,7 +311,7 @@ static switch_status_t add_stream(OutputStream *ost, AVFormatContext *oc, AVCode
}
/* Some formats want stream headers to be separate. */
if
(
o
c
->
oformat
->
flags
&
AVFMT_GLOBALHEADER
)
{
if
(
f
c
->
oformat
->
flags
&
AVFMT_GLOBALHEADER
)
{
c
->
flags
|=
CODEC_FLAG_GLOBAL_HEADER
;
}
...
...
@@ -292,10 +340,10 @@ static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, int width, int height)
return
picture
;
}
static
switch_status_t
open_video
(
AVFormatContext
*
oc
,
AVCodec
*
codec
,
OutputStream
*
o
st
)
static
switch_status_t
open_video
(
AVFormatContext
*
fc
,
AVCodec
*
codec
,
MediaStream
*
m
st
)
{
int
ret
;
AVCodecContext
*
c
=
o
st
->
st
->
codec
;
AVCodecContext
*
c
=
m
st
->
st
->
codec
;
switch_status_t
status
=
SWITCH_STATUS_FALSE
;
/* open the codec */
...
...
@@ -306,8 +354,8 @@ static switch_status_t open_video(AVFormatContext *oc, AVCodec *codec, OutputStr
}
/* allocate and init a re-usable frame */
o
st
->
frame
=
alloc_picture
(
c
->
pix_fmt
,
c
->
width
,
c
->
height
);
switch_assert
(
o
st
->
frame
);
m
st
->
frame
=
alloc_picture
(
c
->
pix_fmt
,
c
->
width
,
c
->
height
);
switch_assert
(
m
st
->
frame
);
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "pix_fmt: %d\n", c->pix_fmt);
switch_assert
(
c
->
pix_fmt
==
AV_PIX_FMT_YUV420P
);
// always I420 for NOW
...
...
@@ -315,13 +363,13 @@ static switch_status_t open_video(AVFormatContext *oc, AVCodec *codec, OutputStr
return
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
open_audio
(
AVFormatContext
*
oc
,
AVCodec
*
codec
,
OutputStream
*
o
st
)
static
switch_status_t
open_audio
(
AVFormatContext
*
fc
,
AVCodec
*
codec
,
MediaStream
*
m
st
)
{
AVCodecContext
*
c
;
int
ret
;
switch_status_t
status
=
SWITCH_STATUS_FALSE
;
c
=
o
st
->
st
->
codec
;
c
=
m
st
->
st
->
codec
;
ret
=
avcodec_open2
(
c
,
codec
,
NULL
);
if
(
ret
<
0
)
{
...
...
@@ -329,64 +377,64 @@ static switch_status_t open_audio(AVFormatContext *oc, AVCodec *codec, OutputStr
return
status
;
}
o
st
->
frame
=
av_frame_alloc
();
switch_assert
(
o
st
->
frame
);
m
st
->
frame
=
av_frame_alloc
();
switch_assert
(
m
st
->
frame
);
o
st
->
frame
->
sample_rate
=
c
->
sample_rate
;
o
st
->
frame
->
format
=
AV_SAMPLE_FMT_S16
;
o
st
->
frame
->
channel_layout
=
c
->
channel_layout
;
m
st
->
frame
->
sample_rate
=
c
->
sample_rate
;
m
st
->
frame
->
format
=
AV_SAMPLE_FMT_S16
;
m
st
->
frame
->
channel_layout
=
c
->
channel_layout
;
if
(
c
->
codec
->
capabilities
&
CODEC_CAP_VARIABLE_FRAME_SIZE
)
{
o
st
->
frame
->
nb_samples
=
10000
;
m
st
->
frame
->
nb_samples
=
10000
;
}
else
{
o
st
->
frame
->
nb_samples
=
c
->
frame_size
;
m
st
->
frame
->
nb_samples
=
c
->
frame_size
;
}
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_NOTICE
,
"sample_rate: %d nb_samples: %d
\n
"
,
ost
->
frame
->
sample_rate
,
o
st
->
frame
->
nb_samples
);
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_NOTICE
,
"sample_rate: %d nb_samples: %d
\n
"
,
mst
->
frame
->
sample_rate
,
m
st
->
frame
->
nb_samples
);
if
(
c
->
sample_fmt
!=
AV_SAMPLE_FMT_S16
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_NOTICE
,
"sample_fmt %d != AV_SAMPLE_FMT_S16, start resampler
\n
"
,
c
->
sample_fmt
);
o
st
->
resample_ctx
=
avresample_alloc_context
();
m
st
->
resample_ctx
=
avresample_alloc_context
();
if
(
!
o
st
->
resample_ctx
)
{
if
(
!
m
st
->
resample_ctx
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not allocate resampler context
\n
"
);
return
status
;
}
/* set options */
av_opt_set_int
(
o
st
->
resample_ctx
,
"in_channel_count"
,
c
->
channels
,
0
);
av_opt_set_int
(
o
st
->
resample_ctx
,
"in_sample_rate"
,
c
->
sample_rate
,
0
);
av_opt_set_int
(
o
st
->
resample_ctx
,
"in_sample_fmt"
,
AV_SAMPLE_FMT_S16
,
0
);
av_opt_set_int
(
o
st
->
resample_ctx
,
"in_channel_layout"
,
c
->
channel_layout
,
0
);
av_opt_set_int
(
o
st
->
resample_ctx
,
"out_channel_count"
,
c
->
channels
,
0
);
av_opt_set_int
(
o
st
->
resample_ctx
,
"out_sample_rate"
,
c
->
sample_rate
,
0
);
av_opt_set_int
(
o
st
->
resample_ctx
,
"out_sample_fmt"
,
c
->
sample_fmt
,
0
);
av_opt_set_int
(
o
st
->
resample_ctx
,
"out_channel_layout"
,
c
->
channel_layout
,
0
);
if
((
ret
=
avresample_open
(
o
st
->
resample_ctx
))
<
0
)
{
av_opt_set_int
(
m
st
->
resample_ctx
,
"in_channel_count"
,
c
->
channels
,
0
);
av_opt_set_int
(
m
st
->
resample_ctx
,
"in_sample_rate"
,
c
->
sample_rate
,
0
);
av_opt_set_int
(
m
st
->
resample_ctx
,
"in_sample_fmt"
,
AV_SAMPLE_FMT_S16
,
0
);
av_opt_set_int
(
m
st
->
resample_ctx
,
"in_channel_layout"
,
c
->
channel_layout
,
0
);
av_opt_set_int
(
m
st
->
resample_ctx
,
"out_channel_count"
,
c
->
channels
,
0
);
av_opt_set_int
(
m
st
->
resample_ctx
,
"out_sample_rate"
,
c
->
sample_rate
,
0
);
av_opt_set_int
(
m
st
->
resample_ctx
,
"out_sample_fmt"
,
c
->
sample_fmt
,
0
);
av_opt_set_int
(
m
st
->
resample_ctx
,
"out_channel_layout"
,
c
->
channel_layout
,
0
);
if
((
ret
=
avresample_open
(
m
st
->
resample_ctx
))
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to initialize the resampling context
\n
"
);
return
status
;
}
}
ret
=
av_frame_get_buffer
(
o
st
->
frame
,
0
);
ret
=
av_frame_get_buffer
(
m
st
->
frame
,
0
);
if
(
ret
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not allocate audio frame.
\n
"
);
return
status
;
}
if
(
o
st
->
resample_ctx
)
{
o
st
->
tmp_frame
=
av_frame_alloc
();
switch_assert
(
o
st
->
tmp_frame
);
if
(
m
st
->
resample_ctx
)
{
m
st
->
tmp_frame
=
av_frame_alloc
();
switch_assert
(
m
st
->
tmp_frame
);
o
st
->
tmp_frame
->
sample_rate
=
c
->
sample_rate
;
o
st
->
tmp_frame
->
format
=
c
->
sample_fmt
;
o
st
->
tmp_frame
->
channel_layout
=
c
->
channel_layout
;
ost
->
tmp_frame
->
nb_samples
=
o
st
->
frame
->
nb_samples
;
m
st
->
tmp_frame
->
sample_rate
=
c
->
sample_rate
;
m
st
->
tmp_frame
->
format
=
c
->
sample_fmt
;
m
st
->
tmp_frame
->
channel_layout
=
c
->
channel_layout
;
mst
->
tmp_frame
->
nb_samples
=
m
st
->
frame
->
nb_samples
;
ret
=
av_frame_get_buffer
(
o
st
->
tmp_frame
,
0
);
ret
=
av_frame_get_buffer
(
m
st
->
tmp_frame
,
0
);
if
(
ret
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not allocate audio frame.
\n
"
);
return
status
;
...
...
@@ -473,7 +521,7 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *
if
(
got_packet
)
{
switch_mutex_lock
(
eh
->
mutex
);
ret
=
write_frame
(
eh
->
o
c
,
&
eh
->
video_st
->
st
->
codec
->
time_base
,
eh
->
video_st
->
st
,
&
pkt
);
ret
=
write_frame
(
eh
->
f
c
,
&
eh
->
video_st
->
st
->
codec
->
time_base
,
eh
->
video_st
->
st
,
&
pkt
);
switch_mutex_unlock
(
eh
->
mutex
);
av_free_packet
(
&
pkt
);
}
...
...
@@ -509,11 +557,14 @@ static switch_status_t video_read_callback(switch_core_session_t *session, switc
return
SWITCH_STATUS_SUCCESS
;;
}
static
void
close_stream
(
AVFormatContext
*
oc
,
OutputStream
*
o
st
)
static
void
close_stream
(
AVFormatContext
*
fc
,
MediaStream
*
m
st
)
{
avcodec_close
(
ost
->
st
->
codec
);
av_frame_free
(
&
ost
->
frame
);
if
(
ost
->
tmp_frame
)
av_frame_free
(
&
ost
->
tmp_frame
);
if
(
mst
->
resample_ctx
)
avresample_close
(
mst
->
resample_ctx
);
if
(
mst
->
sws_ctx
)
sws_freeContext
(
mst
->
sws_ctx
);
if
(
mst
->
frame
)
av_frame_free
(
&
mst
->
frame
);
if
(
mst
->
tmp_frame
)
av_frame_free
(
&
mst
->
tmp_frame
);
avcodec_close
(
mst
->
st
->
codec
);
}
SWITCH_STANDARD_APP
(
record_av_function
)
...
...
@@ -532,10 +583,10 @@ SWITCH_STANDARD_APP(record_av_function)
switch_vid_params_t
vid_params
=
{
0
};
int
force_sample_rate
;
Output
Stream
video_st
=
{
0
},
audio_st
=
{
0
};
Media
Stream
video_st
=
{
0
},
audio_st
=
{
0
};
AVOutputFormat
*
fmt
=
NULL
;
const
char
*
format
=
NULL
;
AVFormatContext
*
o
c
=
NULL
;
AVFormatContext
*
f
c
=
NULL
;
AVCodec
*
audio_codec
,
*
video_codec
;
int
has_audio
=
0
,
has_video
=
0
;
int
ret
;
...
...
@@ -582,18 +633,18 @@ SWITCH_STANDARD_APP(record_av_function)
switch_buffer_create_dynamic
(
&
buffer
,
8192
,
65536
,
0
);
av_register_all
();
avformat_alloc_output_context2
(
&
o
c
,
NULL
,
format
,
data
);
avformat_alloc_output_context2
(
&
f
c
,
NULL
,
format
,
data
);
if
(
!
o
c
)
{
if
(
!
f
c
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Could not deduce output format from file extension
\n
"
);
goto
end
;
}
fmt
=
o
c
->
oformat
;
fmt
=
f
c
->
oformat
;
/* open the output file, if needed */
if
(
!
(
fmt
->
flags
&
AVFMT_NOFILE
))
{
ret
=
avio_open
(
&
o
c
->
pb
,
data
,
AVIO_FLAG_WRITE
);
ret
=
avio_open
(
&
f
c
->
pb
,
data
,
AVIO_FLAG_WRITE
);
if
(
ret
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not open '%s': %s
\n
"
,
data
,
get_error_text
(
ret
));
goto
end
;
...
...
@@ -621,8 +672,8 @@ SWITCH_STANDARD_APP(record_av_function)
video_st
.
width
=
vid_params
.
width
;
video_st
.
height
=
vid_params
.
height
;
video_st
.
next_pts
=
switch_time_now
()
/
1000
;
if
(
add_stream
(
&
video_st
,
o
c
,
&
video_codec
,
fmt
->
video_codec
,
NULL
)
==
SWITCH_STATUS_SUCCESS
&&
open_video
(
o
c
,
video_codec
,
&
video_st
)
==
SWITCH_STATUS_SUCCESS
)
{
if
(
add_stream
(
&
video_st
,
f
c
,
&
video_codec
,
fmt
->
video_codec
,
NULL
)
==
SWITCH_STATUS_SUCCESS
&&
open_video
(
f
c
,
video_codec
,
&
video_st
)
==
SWITCH_STATUS_SUCCESS
)
{
avcodec_string
(
codec_str
,
sizeof
(
codec_str
),
video_st
.
st
->
codec
,
1
);
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_INFO
,
"use video codec implementation %s
\n
"
,
codec_str
);
has_video
=
1
;
...
...
@@ -633,18 +684,18 @@ SWITCH_STANDARD_APP(record_av_function)
audio_st
.
channels
=
read_impl
.
number_of_channels
;
audio_st
.
sample_rate
=
force_sample_rate
;
add_stream
(
&
audio_st
,
o
c
,
&
audio_codec
,
fmt
->
audio_codec
,
NULL
);
if
(
open_audio
(
o
c
,
audio_codec
,
&
audio_st
)
!=
SWITCH_STATUS_SUCCESS
)
{
add_stream
(
&
audio_st
,
f
c
,
&
audio_codec
,
fmt
->
audio_codec
,
NULL
);
if
(
open_audio
(
f
c
,
audio_codec
,
&
audio_st
)
!=
SWITCH_STATUS_SUCCESS
)
{
goto
end
;
}
has_audio
=
1
;
}
av_dump_format
(
o
c
,
0
,
data
,
1
);
av_dump_format
(
f
c
,
0
,
data
,
1
);
/* Write the stream header, if any. */
ret
=
avformat_write_header
(
o
c
,
NULL
);
ret
=
avformat_write_header
(
f
c
,
NULL
);
if
(
ret
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Error occurred when opening output file: %s
\n
"
,
get_error_text
(
ret
));
goto
end
;
...
...
@@ -656,7 +707,7 @@ SWITCH_STANDARD_APP(record_av_function)
switch_mutex_init
(
&
mutex
,
SWITCH_MUTEX_NESTED
,
switch_core_session_get_pool
(
session
));
eh
.
mutex
=
mutex
;
eh
.
video_st
=
&
video_st
;
eh
.
oc
=
o
c
;
eh
.
fc
=
f
c
;
if
(
switch_core_timer_init
(
&
timer
,
"soft"
,
1
,
1
,
switch_core_session_get_pool
(
session
))
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_SESSION_LOG
(
session
),
SWITCH_LOG_ERROR
,
"Timer Activation Fail
\n
"
);
goto
end
;
...
...
@@ -776,7 +827,7 @@ SWITCH_STANDARD_APP(record_av_function)
if
(
got_packet
)
{
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got pkt: %d\n", pkt.size);
ret
=
write_frame
(
o
c
,
&
audio_st
.
st
->
codec
->
time_base
,
audio_st
.
st
,
&
pkt
);
ret
=
write_frame
(
f
c
,
&
audio_st
.
st
->
codec
->
time_base
,
audio_st
.
st
,
&
pkt
);
if
(
ret
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Error while writing audio frame: %s
\n
"
,
get_error_text
(
ret
));
goto
end
;
...
...
@@ -812,31 +863,31 @@ SWITCH_STANDARD_APP(record_av_function)
}
if
(
got_packet
)
{
ret
=
write_frame
(
o
c
,
&
video_st
.
st
->
codec
->
time_base
,
video_st
.
st
,
&
pkt
);
ret
=
write_frame
(
f
c
,
&
video_st
.
st
->
codec
->
time_base
,
video_st
.
st
,
&
pkt
);
av_free_packet
(
&
pkt
);
goto
again
;
}
}
av_write_trailer
(
o
c
);
av_write_trailer
(
f
c
);
switch_channel_set_variable
(
channel
,
SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE
,
"OK"
);
end
:
if
(
o
c
)
{
if
(
has_video
)
close_stream
(
o
c
,
&
video_st
);
if
(
has_audio
)
close_stream
(
o
c
,
&
audio_st
);
if
(
f
c
)
{
if
(
has_video
)
close_stream
(
f
c
,
&
video_st
);
if
(
has_audio
)
close_stream
(
f
c
,
&
audio_st
);
if
(
fmt
)
{
if
(
!
(
fmt
->
flags
&
AVFMT_NOFILE
))
{
avio_close
(
o
c
->
pb
);
avio_close
(
f
c
->
pb
);
}
else
{
avformat_network_deinit
();
}
}
/* free the stream */
avformat_free_context
(
o
c
);
avformat_free_context
(
f
c
);
}
if
(
timer
.
interval
)
{
...
...
@@ -1104,9 +1155,9 @@ struct av_file_context {
int
vid_ready
;
int
audio_ready
;
Output
Stream
video_st
;
Output
Stream
audio_st
;
AVFormatContext
*
o
c
;
Media
Stream
video_st
;
Media
Stream
audio_st
;
AVFormatContext
*
f
c
;
AVCodec
*
audio_codec
;
AVCodec
*
video_codec
;
...
...
@@ -1114,10 +1165,293 @@ struct av_file_context {
int
has_video
;
record_helper_t
eh
;
switch_thread_t
*
file_read_thread
;
int
file_read_thread_running
;
switch_time_t
video_start_time
;
};
typedef
struct
av_file_context
av_file_context_t
;
static
switch_status_t
open_input_file
(
av_file_context_t
*
context
,
switch_file_handle_t
*
handle
,
const
char
*
filename
)
{
AVCodec
*
audio_codec
;
AVCodec
*
video_codec
;
int
error
;
int
i
;
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
/** Open the input file to read from it. */
if
((
error
=
avformat_open_input
(
&
context
->
fc
,
filename
,
NULL
,
NULL
))
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not open input file '%s' (error '%s')
\n
"
,
filename
,
get_error_text
(
error
));
switch_goto_status
(
SWITCH_STATUS_FALSE
,
err
);
}
/** Get information on the input file (number of streams etc.). */
if
((
error
=
avformat_find_stream_info
(
context
->
fc
,
NULL
))
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not open find stream info (error '%s')
\n
"
,
get_error_text
(
error
));
switch_goto_status
(
SWITCH_STATUS_FALSE
,
err
);
}
av_dump_format
(
context
->
fc
,
0
,
filename
,
0
);
for
(
i
=
0
;
i
<
context
->
fc
->
nb_streams
;
i
++
)
{
if
(
context
->
fc
->
streams
[
i
]
->
codec
->
codec_type
==
AVMEDIA_TYPE_AUDIO
&&
!
context
->
has_audio
)
{
context
->
audio_st
.
st
=
context
->
fc
->
streams
[
i
];
context
->
has_audio
=
1
;
}
else
if
(
context
->
fc
->
streams
[
i
]
->
codec
->
codec_type
==
AVMEDIA_TYPE_VIDEO
&&
!
context
->
has_video
)
{
context
->
video_st
.
st
=
context
->
fc
->
streams
[
i
];
context
->
has_video
=
1
;
}
}
/** Find a decoder for the audio stream. */
if
(
context
->
has_audio
&&
!
(
audio_codec
=
avcodec_find_decoder
(
context
->
audio_st
.
st
->
codec
->
codec_id
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Could not find input codec %d
\n
"
,
context
->
audio_st
.
st
->
codec
->
codec_id
);
context
->
has_audio
=
0
;
}
if
(
context
->
has_video
&&
!
(
video_codec
=
avcodec_find_decoder
(
context
->
video_st
.
st
->
codec
->
codec_id
)))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not find input codec %d
\n
"
,
context
->
video_st
.
st
->
codec
->
codec_id
);
context
->
has_video
=
0
;
}
if
(
context
->
has_audio
&&
(
error
=
avcodec_open2
(
context
->
audio_st
.
st
->
codec
,
audio_codec
,
NULL
))
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not open input codec (error '%s')
\n
"
,
get_error_text
(
error
));
context
->
has_audio
=
0
;
}
if
(
context
->
has_video
&&
(
error
=
avcodec_open2
(
context
->
video_st
.
st
->
codec
,
video_codec
,
NULL
))
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not open input codec (error '%s')
\n
"
,
get_error_text
(
error
));
context
->
has_video
=
0
;
}
// printf("has audio:%d has_video:%d\n", context->has_audio, context->has_video);
if
((
!
context
->
has_audio
)
&&
(
!
context
->
has_video
))
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Neither audio nor video stream found in file %s
\n
"
,
filename
);
switch_goto_status
(
SWITCH_STATUS_FALSE
,
err
);
}
if
(
context
->
has_audio
)
{
context
->
audio_st
.
frame
=
av_frame_alloc
();
switch_assert
(
context
->
audio_st
.
frame
);
AVCodecContext
*
c
=
context
->
audio_st
.
st
->
codec
;
handle
->
channels
=
c
->
channels
>
2
?
2
:
c
->
channels
;
context
->
audio_st
.
channels
=
handle
->
channels
;
context
->
audio_st
.
sample_rate
=
handle
->
samplerate
;
if
(
context
->
audio_st
.
st
->
codec
->
sample_fmt
!=
AV_SAMPLE_FMT_S16
)
{
AVAudioResampleContext
*
resample_ctx
=
avresample_alloc_context
();
if
(
resample_ctx
)
{
int
ret
;
av_opt_set_int
(
resample_ctx
,
"in_channel_count"
,
c
->
channels
,
0
);
av_opt_set_int
(
resample_ctx
,
"in_sample_rate"
,
c
->
sample_rate
,
0
);
av_opt_set_int
(
resample_ctx
,
"in_sample_fmt"
,
c
->
sample_fmt
,
0
);
av_opt_set_int
(
resample_ctx
,
"in_channel_layout"
,
c
->
channel_layout
,
0
);
av_opt_set_int
(
resample_ctx
,
"out_channel_count"
,
handle
->
channels
,
0
);
av_opt_set_int
(
resample_ctx
,
"out_sample_rate"
,
handle
->
samplerate
,
0
);
av_opt_set_int
(
resample_ctx
,
"out_sample_fmt"
,
AV_SAMPLE_FMT_S16
,
0
);
av_opt_set_int
(
resample_ctx
,
"out_channel_layout"
,
handle
->
channels
==
2
?
AV_CH_LAYOUT_STEREO
:
AV_CH_LAYOUT_MONO
,
0
);
if
((
ret
=
avresample_open
(
resample_ctx
))
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Failed to initialize the resampling context
\n
"
);
av_free
(
resample_ctx
);
switch_goto_status
(
SWITCH_STATUS_FALSE
,
err
);
}
context
->
audio_st
.
resample_ctx
=
resample_ctx
;
}
}
}
return
status
;
err:
if
(
context
->
fc
)
avformat_close_input
(
&
context
->
fc
);
return
status
;
}
static
void
*
SWITCH_THREAD_FUNC
file_read_thread_run
(
switch_thread_t
*
thread
,
void
*
obj
)
{
av_file_context_t
*
context
=
(
av_file_context_t
*
)
obj
;
AVPacket
pkt
=
{
0
};
int
got_data
=
0
;
int
error
;
context
->
file_read_thread_running
=
1
;
#define AUDIO_BUF_SEC 5
while
(
context
->
file_read_thread_running
)
{
if
(
switch_buffer_inuse
(
context
->
audio_buffer
)
>
AUDIO_BUF_SEC
*
context
->
audio_st
.
sample_rate
*
context
->
audio_st
.
channels
*
2
)
{
switch_yield
(
100000
);
continue
;
}
av_init_packet
(
&
pkt
);
pkt
.
data
=
NULL
;
pkt
.
size
=
0
;
if
((
error
=
av_read_frame
(
context
->
fc
,
&
pkt
))
<
0
)
{
if
(
error
==
AVERROR_EOF
)
break
;
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not read frame (error '%s')
\n
"
,
get_error_text
(
error
));
break
;
}
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "stream: %d, pkt size %d\n", pkt.stream_index, pkt.size);
if
(
context
->
has_video
&&
pkt
.
stream_index
==
context
->
video_st
.
st
->
index
)
{
AVFrame
*
vframe
=
av_frame_alloc
();
switch_image_t
*
img
;
switch_assert
(
vframe
);
if
((
error
=
avcodec_decode_video2
(
context
->
video_st
.
st
->
codec
,
vframe
,
&
got_data
,
&
pkt
))
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not decode frame (error '%s')
\n
"
,
get_error_text
(
error
));
av_free_packet
(
&
pkt
);
av_frame_free
(
&
vframe
);
break
;
}
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "pkt: %d, pts: %lld dts: %lld\n", pkt.size, pkt.pts, pkt.dts);
av_free_packet
(
&
pkt
);
if
(
switch_queue_size
(
context
->
eh
.
video_queue
)
>
300
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Dropping frames
\n
"
);
av_frame_free
(
&
vframe
);
continue
;
}
if
(
got_data
&&
error
>
0
)
{
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got picture %dx%d fmt: %d pktpts:%lld pktdts:%lld\n", vframe->width, vframe->height, vframe->format, vframe->pkt_pts, vframe->pkt_dts);
if
(
vframe
->
format
!=
AV_PIX_FMT_YUV420P
)
{
AVFrame
*
frm
=
vframe
;
int
ret
;
if
(
!
context
->
video_st
.
sws_ctx
)
{
context
->
video_st
.
sws_ctx
=
sws_getContext
(
frm
->
width
,
frm
->
height
,
frm
->
format
,
frm
->
width
,
frm
->
height
,
AV_PIX_FMT_YUV420P
,
SCALE_FLAGS
,
NULL
,
NULL
,
NULL
);
if
(
!
context
->
video_st
.
sws_ctx
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Cannot init sws context
\n
"
);
av_frame_free
(
&
frm
);
continue
;
}
}
vframe
=
av_frame_alloc
();
switch_assert
(
vframe
);
vframe
->
format
=
AV_PIX_FMT_YUV420P
;
vframe
->
width
=
frm
->
width
;
vframe
->
height
=
frm
->
height
;
vframe
->
pts
=
frm
->
pts
;
vframe
->
pkt_pts
=
frm
->
pkt_pts
;
vframe
->
pkt_dts
=
frm
->
pkt_dts
;
ret
=
av_frame_get_buffer
(
vframe
,
32
);
switch_assert
(
ret
>=
0
);
ret
=
sws_scale
(
context
->
video_st
.
sws_ctx
,
(
const
uint8_t
*
const
*
)
frm
->
data
,
frm
->
linesize
,
0
,
frm
->
height
,
vframe
->
data
,
vframe
->
linesize
);
av_frame_free
(
&
frm
);
if
(
ret
<=
0
)
{
av_frame_free
(
&
vframe
);
continue
;
}
}
img
=
switch_img_alloc
(
NULL
,
SWITCH_IMG_FMT_I420
,
vframe
->
width
,
vframe
->
height
,
1
);
if
(
img
)
{
uint64_t
*
pts
=
malloc
(
sizeof
(
uint64_t
));
if
(
pts
)
{
*
pts
=
vframe
->
pkt_pts
;
avframe2img
(
vframe
,
img
);
img
->
user_priv
=
pts
;
switch_queue_push
(
context
->
eh
.
video_queue
,
img
);
}
}
av_frame_free
(
&
vframe
);
}
continue
;
}
else
if
(
context
->
has_audio
&&
pkt
.
stream_index
==
context
->
audio_st
.
st
->
index
)
{
AVFrame
in_frame
=
{
{
0
}
};
if
((
error
=
avcodec_decode_audio4
(
context
->
audio_st
.
st
->
codec
,
&
in_frame
,
&
got_data
,
&
pkt
))
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not decode frame (error '%s')
\n
"
,
get_error_text
(
error
));
av_free_packet
(
&
pkt
);
break
;
}
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "pkt: %d, decodedddd: %d pts: %lld dts: %lld\n", pkt.size, error, pkt.pts, pkt.dts);
av_free_packet
(
&
pkt
);
if
(
got_data
)
{
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got data frm->format: %d samples: %d\n", in_frame.format, in_frame.nb_samples);
if
(
context
->
audio_st
.
resample_ctx
)
{
int
out_samples
=
avresample_get_out_samples
(
context
->
audio_st
.
resample_ctx
,
in_frame
.
nb_samples
);
int
ret
;
uint8_t
*
data
[
2
]
=
{
0
};
data
[
0
]
=
malloc
(
out_samples
*
context
->
audio_st
.
channels
*
2
);
switch_assert
(
data
[
0
]);
ret
=
avresample_convert
(
context
->
audio_st
.
resample_ctx
,
data
,
0
,
out_samples
,
in_frame
.
data
,
0
,
in_frame
.
nb_samples
);
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "out_samples: %d ret: %d delay: %d buffer: %zu\n", out_samples, ret, avresample_get_delay(context->audio_st.resample_ctx), switch_buffer_inuse(context->audio_buffer));
if
(
ret
)
{
switch_mutex_lock
(
context
->
mutex
);
switch_buffer_write
(
context
->
audio_buffer
,
data
[
0
],
ret
*
2
*
context
->
audio_st
.
channels
);
switch_mutex_unlock
(
context
->
mutex
);
}
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "decoded samples: %d\n", ret);
free
(
data
[
0
]);
// if (ret == 0 && avresample_get_delay(context->audio_st.resample_ctx)) {
// frameP = NULL;
// goto again;
// }
}
else
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"this block is not tested samples: %d
\n
"
,
in_frame
.
nb_samples
);
switch_mutex_lock
(
context
->
mutex
);
switch_buffer_write
(
context
->
audio_buffer
,
in_frame
.
data
[
0
],
in_frame
.
nb_samples
*
2
*
context
->
audio_st
.
channels
);
switch_mutex_unlock
(
context
->
mutex
);
}
}
}
}
if
(
context
->
has_video
)
switch_queue_push
(
context
->
eh
.
video_queue
,
NULL
);
context
->
file_read_thread_running
=
0
;
return
NULL
;
}
static
switch_status_t
av_file_open
(
switch_file_handle_t
*
handle
,
const
char
*
path
)
{
av_file_context_t
*
context
;
...
...
@@ -1131,10 +1465,6 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
switch_set_string
(
file
,
path
);
if
(
switch_test_flag
(
handle
,
SWITCH_FILE_FLAG_READ
))
{
return
SWITCH_STATUS_FALSE
;
}
if
((
ext
=
strrchr
((
char
*
)
path
,
'.'
))
==
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Invalid Format
\n
"
);
return
SWITCH_STATUS_GENERR
;
...
...
@@ -1178,18 +1508,45 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_DEBUG
,
"sample rate: %d, channels: %d
\n
"
,
handle
->
samplerate
,
handle
->
channels
);
av_register_all
();
avformat_alloc_output_context2
(
&
context
->
oc
,
NULL
,
format
,
(
char
*
)
file
);
if
(
!
context
->
oc
)
{
if
(
switch_test_flag
(
handle
,
SWITCH_FILE_FLAG_READ
))
{
if
(
open_input_file
(
context
,
handle
,
path
)
!=
SWITCH_STATUS_SUCCESS
)
{
//clean up;
return
SWITCH_STATUS_GENERR
;
}
handle
->
private_info
=
context
;
context
->
pool
=
handle
->
memory_pool
;
if
(
context
->
has_video
)
{
switch_queue_create
(
&
context
->
eh
.
video_queue
,
SWITCH_CORE_QUEUE_LEN
,
handle
->
memory_pool
);
switch_mutex_init
(
&
context
->
eh
.
mutex
,
SWITCH_MUTEX_NESTED
,
handle
->
memory_pool
);
}
{
switch_threadattr_t
*
thd_attr
=
NULL
;
switch_threadattr_create
(
&
thd_attr
,
handle
->
memory_pool
);
switch_threadattr_stacksize_set
(
thd_attr
,
SWITCH_THREAD_STACKSIZE
);
switch_thread_create
(
&
context
->
file_read_thread
,
thd_attr
,
file_read_thread_run
,
context
,
handle
->
memory_pool
);
}
return
SWITCH_STATUS_SUCCESS
;
}
avformat_alloc_output_context2
(
&
context
->
fc
,
NULL
,
format
,
(
char
*
)
file
);
if
(
!
context
->
fc
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"Could not deduce output format from file extension
\n
"
);
goto
end
;
}
fmt
=
context
->
o
c
->
oformat
;
fmt
=
context
->
f
c
->
oformat
;
/* open the output file, if needed */
if
(
!
(
fmt
->
flags
&
AVFMT_NOFILE
))
{
ret
=
avio_open
(
&
context
->
o
c
->
pb
,
file
,
AVIO_FLAG_WRITE
);
ret
=
avio_open
(
&
context
->
f
c
->
pb
,
file
,
AVIO_FLAG_WRITE
);
if
(
ret
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Could not open '%s': %s
\n
"
,
file
,
get_error_text
(
ret
));
goto
end
;
...
...
@@ -1256,15 +1613,15 @@ static switch_status_t av_file_open(switch_file_handle_t *handle, const char *pa
context
->
audio_st
.
channels
=
handle
->
channels
;
context
->
audio_st
.
sample_rate
=
handle
->
samplerate
;
add_stream
(
&
context
->
audio_st
,
context
->
o
c
,
&
context
->
audio_codec
,
fmt
->
audio_codec
,
&
handle
->
mm
);
if
(
open_audio
(
context
->
o
c
,
context
->
audio_codec
,
&
context
->
audio_st
)
!=
SWITCH_STATUS_SUCCESS
)
{
add_stream
(
&
context
->
audio_st
,
context
->
f
c
,
&
context
->
audio_codec
,
fmt
->
audio_codec
,
&
handle
->
mm
);
if
(
open_audio
(
context
->
f
c
,
context
->
audio_codec
,
&
context
->
audio_st
)
!=
SWITCH_STATUS_SUCCESS
)
{
goto
end
;
}
context
->
has_audio
=
1
;
}
av_dump_format
(
context
->
o
c
,
0
,
file
,
1
);
av_dump_format
(
context
->
f
c
,
0
,
file
,
1
);
handle
->
format
=
0
;
handle
->
sections
=
0
;
...
...
@@ -1302,20 +1659,27 @@ static switch_status_t av_file_close(switch_file_handle_t *handle)
switch_thread_join
(
&
status
,
context
->
eh
.
video_thread
);
}
if
(
context
->
oc
)
{
av_write_trailer
(
context
->
oc
);
if
(
context
->
file_read_thread_running
&&
context
->
file_read_thread
)
{
context
->
file_read_thread_running
=
0
;
switch_thread_join
(
&
status
,
context
->
file_read_thread
);
}
if
(
context
->
fc
)
{
if
(
switch_test_flag
(
handle
,
SWITCH_FILE_FLAG_WRITE
))
av_write_trailer
(
context
->
fc
);
if
(
context
->
has_video
)
close_stream
(
context
->
o
c
,
&
context
->
video_st
);
if
(
context
->
has_audio
)
close_stream
(
context
->
o
c
,
&
context
->
audio_st
);
if
(
context
->
has_video
)
close_stream
(
context
->
f
c
,
&
context
->
video_st
);
if
(
context
->
has_audio
)
close_stream
(
context
->
f
c
,
&
context
->
audio_st
);
if
(
!
(
context
->
oc
->
oformat
->
flags
&
AVFMT_NOFILE
))
{
avio_close
(
context
->
oc
->
pb
);
if
(
context
->
fc
->
oformat
)
{
if
(
!
(
context
->
fc
->
oformat
->
flags
&
AVFMT_NOFILE
))
{
avio_close
(
context
->
fc
->
pb
);
//todo
}
else
{
avformat_network_deinit
();
}
}
/* free the stream */
avformat_free_context
(
context
->
o
c
);
avformat_free_context
(
context
->
f
c
);
}
if
(
context
->
timer
.
interval
)
{
...
...
@@ -1335,8 +1699,38 @@ static switch_status_t av_file_seek(switch_file_handle_t *handle, unsigned int *
static
switch_status_t
av_file_read
(
switch_file_handle_t
*
handle
,
void
*
data
,
size_t
*
len
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"read not implemented
\n
"
);
av_file_context_t
*
context
=
(
av_file_context_t
*
)
handle
->
private_info
;
int
size
;
if
(
!
context
->
has_audio
&&
context
->
has_video
&&
switch_queue_size
(
context
->
eh
.
video_queue
)
>
0
)
{
memset
(
data
,
0
,
*
len
*
handle
->
channels
*
2
);
return
SWITCH_STATUS_SUCCESS
;
}
again:
if
(
!
context
->
file_read_thread_running
&&
switch_buffer_inuse
(
context
->
audio_buffer
)
==
0
)
{
*
len
=
0
;
return
SWITCH_STATUS_FALSE
;
}
switch_mutex_lock
(
context
->
mutex
);
size
=
switch_buffer_inuse
(
context
->
audio_buffer
);
if
(
size
>
*
len
*
context
->
audio_st
.
channels
*
2
)
size
=
*
len
*
context
->
audio_st
.
channels
*
2
;
if
(
size
)
size
=
switch_buffer_read
(
context
->
audio_buffer
,
data
,
size
);
switch_mutex_unlock
(
context
->
mutex
);
if
(
size
==
0
)
{
switch_yield
(
20000
);
goto
again
;
}
*
len
=
size
/
context
->
audio_st
.
channels
/
2
;
handle
->
pos
+=
*
len
;
handle
->
sample_count
+=
*
len
;
return
*
len
==
0
?
SWITCH_STATUS_FALSE
:
SWITCH_STATUS_SUCCESS
;
}
static
switch_status_t
av_file_write
(
switch_file_handle_t
*
handle
,
void
*
data
,
size_t
*
len
)
...
...
@@ -1419,7 +1813,7 @@ static switch_status_t av_file_write(switch_file_handle_t *handle, void *data, s
if
(
got_packet
)
{
if
(
context
->
mutex
)
switch_mutex_lock
(
context
->
mutex
);
ret
=
write_frame
(
context
->
o
c
,
&
context
->
audio_st
.
st
->
codec
->
time_base
,
context
->
audio_st
.
st
,
&
pkt
);
ret
=
write_frame
(
context
->
f
c
,
&
context
->
audio_st
.
st
->
codec
->
time_base
,
context
->
audio_st
.
st
,
&
pkt
);
if
(
context
->
mutex
)
switch_mutex_unlock
(
context
->
mutex
);
if
(
ret
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Error while writing audio frame: %s
\n
"
,
get_error_text
(
ret
));
...
...
@@ -1438,7 +1832,106 @@ end:
static
switch_status_t
av_file_read_video
(
switch_file_handle_t
*
handle
,
switch_frame_t
*
frame
,
switch_video_read_flag_t
flags
)
{
av_file_context_t
*
context
=
(
av_file_context_t
*
)
handle
->
private_info
;
void
*
pop
;
MediaStream
*
mst
=
&
context
->
video_st
;
AVStream
*
st
=
mst
->
st
;
int
ticks
=
0
;
switch_status_t
status
=
SWITCH_STATUS_SUCCESS
;
if
(
!
context
->
has_video
)
return
SWITCH_STATUS_FALSE
;
if
(
!
context
->
file_read_thread_running
&&
switch_queue_size
(
context
->
eh
.
video_queue
)
==
0
)
{
return
SWITCH_STATUS_FALSE
;
}
if
(
flags
&
SVR_FLUSH
)
{
while
(
switch_queue_size
(
context
->
eh
.
video_queue
)
>
1
)
{
if
(
switch_queue_trypop
(
context
->
eh
.
video_queue
,
&
pop
)
==
SWITCH_STATUS_SUCCESS
)
{
if
(
pop
)
{
switch_image_t
*
img
=
(
switch_image_t
*
)
pop
;
switch_img_free
(
&
img
);
}
}
}
return
SWITCH_STATUS_BREAK
;
}
if
(
st
->
codec
->
time_base
.
num
)
{
ticks
=
st
->
parser
?
st
->
parser
->
repeat_pict
+
1
:
st
->
codec
->
ticks_per_frame
;
// mst->next_pts += ((int64_t)AV_TIME_BASE * st->codec->time_base.num * ticks) / st->codec->time_base.den;
}
if
(
!
context
->
video_start_time
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_INFO
,
"start: %lld ticks: %d ticks_per_frame: %d st num:%d st den:%d codec num:%d codec den:%d start: %lld, duration:%lld nb_frames:%lld q2d:%f
\n
"
,
context
->
video_start_time
,
ticks
,
st
->
codec
->
ticks_per_frame
,
st
->
time_base
.
num
,
st
->
time_base
.
den
,
st
->
codec
->
time_base
.
num
,
st
->
codec
->
time_base
.
den
,
st
->
start_time
,
st
->
duration
,
st
->
nb_frames
,
av_q2d
(
st
->
time_base
));
}
again:
if
(
0
)
goto
again
;
if
(
flags
&
SVR_BLOCK
)
{
status
=
switch_queue_pop
(
context
->
eh
.
video_queue
,
&
pop
);
}
else
{
status
=
switch_queue_trypop
(
context
->
eh
.
video_queue
,
&
pop
);
}
if
(
pop
&&
status
==
SWITCH_STATUS_SUCCESS
)
{
switch_image_t
*
img
=
(
switch_image_t
*
)
pop
;
// #define YIELD 60000 // use a constant FPS
#ifdef YIELD
switch_yield
(
YIELD
);
#else
uint64_t
pts
;
uint64_t
now
=
switch_micro_time_now
();
pts
=
av_rescale_q
(
*
((
uint64_t
*
)
img
->
user_priv
),
st
->
time_base
,
AV_TIME_BASE_Q
);
if
(
!
context
->
video_start_time
)
{
context
->
video_start_time
=
now
-
pts
;
}
if
(
st
->
time_base
.
num
==
0
)
{
mst
->
next_pts
=
0
;
}
else
{
// uint64_t last_pts = mst->next_pts;
mst
->
next_pts
=
context
->
video_start_time
+
pts
;
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "pts: %lld last_pts: %lld delta: %lld frame_pts: %lld nextpts: %lld, num: %d, den:%d num:%d den:%d sleep: %lld\n",
// pts, last_pts, mst->next_pts - last_pts, *((uint64_t *)img->user_priv), mst->next_pts, st->time_base.num, st->time_base.den, st->codec->time_base.num, st->codec->time_base.den, mst->next_pts - now);
}
if
(
pts
==
0
)
mst
->
next_pts
=
0
;
if
(
mst
->
next_pts
&&
switch_micro_time_now
()
-
mst
->
next_pts
>
AV_TIME_BASE
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_WARNING
,
"picture is too late, diff: %lld %u
\n
"
,
switch_micro_time_now
()
-
mst
->
next_pts
,
switch_queue_size
(
context
->
eh
.
video_queue
));
switch_img_free
(
&
img
);
// return SWITCH_STATUS_BREAK;
goto
again
;
}
while
(
switch_micro_time_now
()
-
mst
->
next_pts
<
-
10000LL
/
2
)
{
if
(
!
(
flags
&
SVR_BLOCK
))
{
switch_img_free
(
&
img
);
return
SWITCH_STATUS_BREAK
;
}
// switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "yield\n");
switch_yield
(
10000
);
}
#endif
frame
->
img
=
img
;
}
else
{
if
((
flags
&
SVR_BLOCK
))
{
switch_yield
(
10000
);
}
return
SWITCH_STATUS_BREAK
;
}
return
frame
->
img
?
SWITCH_STATUS_SUCCESS
:
SWITCH_STATUS_FALSE
;
}
static
switch_status_t
av_file_write_video
(
switch_file_handle_t
*
handle
,
switch_frame_t
*
frame
)
...
...
@@ -1454,8 +1947,8 @@ static switch_status_t av_file_write_video(switch_file_handle_t *handle, switch_
context
->
video_st
.
width
=
frame
->
img
->
d_w
;
context
->
video_st
.
height
=
frame
->
img
->
d_h
;
context
->
video_st
.
next_pts
=
switch_time_now
()
/
1000
;
if
(
add_stream
(
&
context
->
video_st
,
context
->
oc
,
&
context
->
video_codec
,
context
->
o
c
->
oformat
->
video_codec
,
&
handle
->
mm
)
==
SWITCH_STATUS_SUCCESS
&&
open_video
(
context
->
o
c
,
context
->
video_codec
,
&
context
->
video_st
)
==
SWITCH_STATUS_SUCCESS
)
{
if
(
add_stream
(
&
context
->
video_st
,
context
->
fc
,
&
context
->
video_codec
,
context
->
f
c
->
oformat
->
video_codec
,
&
handle
->
mm
)
==
SWITCH_STATUS_SUCCESS
&&
open_video
(
context
->
f
c
,
context
->
video_codec
,
&
context
->
video_st
)
==
SWITCH_STATUS_SUCCESS
)
{
char
codec_str
[
256
];
int
ret
;
...
...
@@ -1464,9 +1957,9 @@ static switch_status_t av_file_write_video(switch_file_handle_t *handle, switch_
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_INFO
,
"use video codec implementation %s
\n
"
,
codec_str
);
context
->
has_video
=
1
;
// av_dump_format(context->
o
c, 0, "/tmp/av.mp4", 1);
// av_dump_format(context->
f
c, 0, "/tmp/av.mp4", 1);
ret
=
avformat_write_header
(
context
->
o
c
,
NULL
);
ret
=
avformat_write_header
(
context
->
f
c
,
NULL
);
if
(
ret
<
0
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Error occurred when opening output file: %s
\n
"
,
get_error_text
(
ret
));
switch_goto_status
(
SWITCH_STATUS_FALSE
,
end
);
...
...
@@ -1484,7 +1977,7 @@ static switch_status_t av_file_write_video(switch_file_handle_t *handle, switch_
switch_mutex_init
(
&
context
->
mutex
,
SWITCH_MUTEX_NESTED
,
handle
->
memory_pool
);
context
->
eh
.
mutex
=
context
->
mutex
;
context
->
eh
.
video_st
=
&
context
->
video_st
;
context
->
eh
.
oc
=
context
->
o
c
;
context
->
eh
.
fc
=
context
->
f
c
;
if
(
switch_core_timer_init
(
&
context
->
timer
,
"soft"
,
1
,
1
,
handle
->
memory_pool
)
!=
SWITCH_STATUS_SUCCESS
)
{
switch_log_printf
(
SWITCH_CHANNEL_LOG
,
SWITCH_LOG_ERROR
,
"Timer Activation Fail
\n
"
);
switch_goto_status
(
SWITCH_STATUS_FALSE
,
end
);
...
...
@@ -1534,6 +2027,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avformat_load)
supported_formats
[
i
++
]
=
"av"
;
supported_formats
[
i
++
]
=
"rtmp"
;
supported_formats
[
i
++
]
=
"mp4"
;
supported_formats
[
i
++
]
=
"mov"
;
/* connect my internal structure to the blank pointer passed to me */
*
module_interface
=
switch_loadable_module_create_module_interface
(
pool
,
modname
);
...
...
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论