Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
A
AVMix
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
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
AVMix
Commits
1e68d12b
Commit
1e68d12b
authored
Mar 22, 2022
by
NzSN
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update
parent
de41646e
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
285 additions
and
48 deletions
+285
-48
AudioTrackMerge.c
AudioTrackMerge.c
+285
-48
No files found.
AudioTrackMerge.c
View file @
1e68d12b
...
...
@@ -7,15 +7,12 @@
#include <libavfilter/buffersink.h>
#include <libavutil/opt.h>
#define INPUT_FMT AV_SAMPLE_FMT_FLTP
#define INPUT_SAMPLE_RATE 44100
#define INPUT_TB_DEN 14112000
#define INPUT_CHANNEL_LAYOUT AV_CH_LAYOUT_STEREO
uint8_t
errstr
[
1024
];
/*****************************************************************************/
/* Declarations */
/*****************************************************************************/
typedef
struct
MixParameters
{
unsigned
int
index
;
AVCodecContext
*
cc
;
AVStream
*
s
;
unsigned
offset
;
...
...
@@ -32,7 +29,7 @@ typedef struct AudioStreamingContext {
typedef
struct
FilteringContext
{
AVFilterGraph
*
graph
;
AVFilterContext
*
src
;
AVFilterContext
*
*
src
;
AVFilterContext
*
sink
;
unsigned
int
numOfSrcs
;
}
FilteringContext
;
...
...
@@ -59,6 +56,7 @@ FilterChain build_filter_chain_mix_part(AVFilterGraph *graph, int num
int
mixing_audios
(
int
numOfStream
,
AudioStreamingContext
*
inputs
[],
AudioStreamingContext
*
output
,
FilteringContext
*
filter
);
int
write_out
(
AudioStreamingContext
*
encoder
,
AVFrame
*
frame
);
int
prepare_audio_encoder
(
AudioStreamingContext
*
encoder
,
AudioStreamingContext
*
decoder
);
...
...
@@ -70,15 +68,42 @@ int add_to_src(AudioStreamingContext *decoder, AVFilterContext *src,
int
process_filtered_frames
(
AudioStreamingContext
*
encoder
,
AVFrame
*
frame
);
static
int
init_filter_graph
(
AVFilterGraph
**
graph
,
AVFilterContext
**
src
,
AVFilterContext
**
src_
,
AVFilterContext
**
sink
,
AudioStreamingContext
*
decoder_1
,
AudioStreamingContext
*
decoder_2
);
/*****************************************************************************/
/* Definitions */
/*****************************************************************************/
void
audioStreamCtx_Release
(
AudioStreamingContext
**
s_ctx
)
{
int
err
=
0
;
AudioStreamingContext
*
ctx
=
*
s_ctx
;
// Format Cleanup
avformat_close_input
(
&
ctx
->
fmt
);
// CoDec context Cleanup
avcodec_free_context
(
&
ctx
->
cc
);
avcodec_close
(
ctx
->
cc
);
}
void
audioStreamCtx_Release_free
(
AudioStreamingContext
**
s_ctx
)
{
audioStreamCtx_Release
(
s_ctx
);
free
(
*
s_ctx
);
*
s_ctx
=
NULL
;
}
void
filterCtx_Release
(
FilteringContext
**
f_ctx
)
{
FilteringContext
*
ctx
=
*
f_ctx
;
avfilter_graph_free
(
&
ctx
->
graph
);
free
(
ctx
->
src
);
free
(
*
f_ctx
);
*
f_ctx
=
NULL
;
}
int
audioMixArbitary
(
int
numOfAudios
,
AudioFile
*
files
[],
AudioFile
*
o_file
)
{
int
err
=
0
;
AudioStreamingContext
*
output_ctx
;
AudioStreamingContext
**
audio_ctx
=
(
AudioStreamingContext
**
)
calloc
(
1
,
numOfAudios
*
sizeof
(
AudioStreamingContext
));
...
...
@@ -112,21 +137,150 @@ int audioMixArbitary(int numOfAudios, AudioFile *files[], AudioFile *o_file) {
goto
FAIL
;
}
return
0
;
goto
CLEANUP
;
FAIL:
/* FIXME: Need to release all allocated resources */
return
1
;
err
=
1
;
CLEANUP:
audioStreamCtx_Release_free
(
&
output_ctx
);
for
(
int
i
=
0
;
i
<
numOfAudios
;
++
i
)
{
audioStreamCtx_Release_free
(
&
audio_ctx
[
i
]);
}
free
(
audio_ctx
);
filterCtx_Release
(
&
filter_ctx
);
return
err
;
}
int
mixing_audios
(
int
numOfStream
,
AudioStreamingContext
*
inputs
[],
AudioStreamingContext
*
output
,
FilteringContext
*
filter
)
{
int
err
=
0
;
AVPacket
*
packet
=
av_packet_alloc
();
AVFrame
*
frame
=
av_frame_alloc
();
AudioStreamingContext
*
asctx
=
NULL
;
int
finCount
=
0
;
_Bool
*
finished
=
(
_Bool
*
)
calloc
(
numOfStream
,
sizeof
(
_Bool
));
while
(
1
)
{
// Read frame from AudioStreams
for
(
int
i
=
0
;
i
<
numOfStream
;
++
i
)
{
// All frame of this stream is readed.
if
(
finished
[
i
]
==
1
)
continue
;
asctx
=
inputs
[
i
];
err
=
av_read_frame
(
asctx
->
fmt
,
packet
);
if
(
err
<
0
)
{
finished
[
i
]
=
1
;
++
finCount
;
err
=
0
;
}
else
{
err
=
avcodec_send_packet
(
asctx
->
cc
,
packet
);
if
(
err
<
0
&&
err
!=
AVERROR
(
EAGAIN
))
{
printf
(
"Failed to send packet to decoder: %s
\n
"
,
av_err2str
(
err
));
goto
Done
;
}
av_packet_unref
(
packet
);
}
// Send an empty frame to notify to filter that this stream
// has no more frames.
if
(
finished
[
i
]
==
1
)
{
err
=
av_buffersrc_add_frame
(
filter
->
src
[
i
],
NULL
);
if
(
err
<
0
)
{
printf
(
"Failed to add frame to filter
\n
"
);
goto
Done
;
}
}
else
{
while
(
err
>=
0
)
{
err
=
avcodec_receive_frame
(
asctx
->
cc
,
frame
);
if
(
err
==
AVERROR
(
EAGAIN
)
||
err
==
AVERROR_EOF
)
{
break
;
}
else
if
(
err
<
0
)
{
printf
(
"Failed to decode frames: %s
\n
"
,
av_err2str
(
err
));
goto
Done
;
}
err
=
av_buffersrc_add_frame
(
filter
->
src
[
i
],
frame
);
if
(
err
<
0
)
{
printf
(
"Failed to filter frame
\n
"
);
goto
Done
;
}
av_frame_unref
(
frame
);
}
}
}
if
(
finCount
==
numOfStream
)
{
err
=
0
;
write_out
(
output
,
NULL
);
break
;
}
// Get filtered frame
while
((
err
=
av_buffersink_get_frame
(
filter
->
sink
,
frame
))
>=
0
)
{
write_out
(
output
,
frame
);
av_frame_unref
(
frame
);
}
}
av_write_trailer
(
output
->
fmt
);
Done:
free
(
finished
);
av_packet_free
(
&
packet
);
av_frame_free
(
&
frame
);
return
err
;
}
int
write_out
(
AudioStreamingContext
*
encoder
,
AVFrame
*
frame
)
{
int
response
=
0
;
AVPacket
*
output_packet
=
av_packet_alloc
();
response
=
avcodec_send_frame
(
encoder
->
cc
,
frame
);
while
(
response
>=
0
)
{
response
=
avcodec_receive_packet
(
encoder
->
cc
,
output_packet
);
if
(
response
==
AVERROR
(
EAGAIN
)
||
response
==
AVERROR_EOF
)
{
break
;
}
else
if
(
response
<
0
)
{
printf
(
"Error while receiving packet from encoder: %s"
,
av_err2str
(
response
));
return
1
;
}
output_packet
->
stream_index
=
0
;
response
=
av_interleaved_write_frame
(
encoder
->
fmt
,
output_packet
);
if
(
response
!=
0
)
{
printf
(
"Error %d while receiving packet from decoder: %s"
,
response
,
av_err2str
(
response
));
return
1
;
}
}
av_packet_unref
(
output_packet
);
av_packet_free
(
&
output_packet
);
return
0
;
}
/* This function create a filter chain for each of input audio medias.
* Filter chain looks like:
* abuffer -> a
setpts
-> amix -> abuffersink
* abuffer -> a
setpts
-----\
* abuffer -> a
delay
-> amix -> abuffersink
* abuffer -> a
delay
-----\
* ........................\
* abuffer -> a
setpts
-----\
* abuffer -> a
delay
-----\
*
* "abuffer -> a
setpts
" is called shift part of filter graph
* "abuffer -> a
delay
" is called shift part of filter graph
* "amix -> abuffersink" is called mix part of filter graph */
FilteringContext
*
create_filter_context
(
int
numOfStream
,
AudioStreamingContext
*
s_ctx
[])
{
int
err
=
0
;
...
...
@@ -147,12 +301,14 @@ FilteringContext* create_filter_context(int numOfStream, AudioStreamingContext *
FilterChain
*
shift_chains
=
(
FilterChain
*
)
malloc
(
numOfStream
*
sizeof
(
FilterChain
));
if
(
shift_chains
->
src
->
nb_inputs
<
numOfStream
)
if
(
mix_chain
.
src
->
nb_inputs
<
(
unsigned
int
)
numOfStream
)
return
NULL
;
for
(
int
i
=
0
;
i
<
numOfStream
;
++
i
)
{
// Create filter chain for shifting purposes for
// each of all input streams
s_ctx
[
i
]
->
mixpar
.
cc
=
s_ctx
[
i
]
->
cc
;
s_ctx
[
i
]
->
mixpar
.
s
=
s_ctx
[
i
]
->
s
;
chain
=
build_filter_chain_shift_part
(
graph
,
s_ctx
[
i
]
->
mixpar
);
shift_chains
[
i
]
=
chain
;
...
...
@@ -162,16 +318,31 @@ FilteringContext* create_filter_context(int numOfStream, AudioStreamingContext *
}
}
// Configure AVFilterGraph
err
=
avfilter_graph_config
(
graph
,
NULL
);
if
(
err
<
0
)
{
goto
FAIL
;
}
char
*
dump
=
avfilter_graph_dump
(
graph
,
NULL
);
av_log
(
NULL
,
AV_LOG_ERROR
,
"Graph:
\n
%s
\n
"
,
dump
);
free
(
dump
);
FilteringContext
*
f_ctx
=
(
FilteringContext
*
)
malloc
(
sizeof
(
FilteringContext
));
f_ctx
->
graph
=
graph
;
f_ctx
->
sink
=
mix_chain
.
sink
;
f_ctx
->
src
=
(
AVFilterContext
**
)
malloc
(
numOfStream
*
sizeof
(
AVFilterContext
*
));
for
(
int
i
=
0
;
i
<
numOfStream
;
++
i
)
{
f_ctx
->
src
=
shift_chains
[
i
].
src
;
f_ctx
->
src
[
i
]
=
shift_chains
[
i
].
src
;
}
free
(
shift_chains
);
return
f_ctx
;
FAIL:
free
(
shift_chains
);
if
(
graph
)
avfilter_graph_free
(
&
graph
);
return
NULL
;
...
...
@@ -179,10 +350,12 @@ FilteringContext* create_filter_context(int numOfStream, AudioStreamingContext *
FilterChain
build_filter_chain_mix_part
(
AVFilterGraph
*
graph
,
int
numOfStreams
)
{
int
err
=
0
;
AVFilterContext
*
amix_ctx
=
NULL
;
AVFilterContext
*
abuffersink_ctx
=
NULL
;
const
AVFilter
*
amix
=
NULL
;
const
AVFilter
*
abuffersink
=
NULL
;
AVFilterContext
*
amix_ctx
=
NULL
;
AVFilterContext
*
abuffersink_ctx
=
NULL
;
AVFilterContext
*
asetnsamples_ctx
=
NULL
;
const
AVFilter
*
amix
=
NULL
;
const
AVFilter
*
asetnsamples
=
NULL
;
const
AVFilter
*
abuffersink
=
NULL
;
/* Create amix filter */
amix
=
avfilter_get_by_name
(
"amix"
);
...
...
@@ -193,7 +366,8 @@ FilterChain build_filter_chain_mix_part(AVFilterGraph *graph, int numOfStreams)
if
(
amix_ctx
==
NULL
)
{
goto
FAIL
;
}
av_opt_set_int
(
amix_ctx
,
"input"
,
numOfStreams
,
AV_OPT_SEARCH_CHILDREN
);
av_opt_set_int
(
amix_ctx
,
"inputs"
,
numOfStreams
,
AV_OPT_SEARCH_CHILDREN
);
av_opt_set
(
amix_ctx
,
"duration"
,
"longest"
,
AV_OPT_SEARCH_CHILDREN
);
err
=
avfilter_init_str
(
amix_ctx
,
NULL
);
if
(
err
<
0
)
{
...
...
@@ -215,11 +389,30 @@ FilterChain build_filter_chain_mix_part(AVFilterGraph *graph, int numOfStreams)
goto
FAIL
;
}
/* Create asetnsamples filter */
asetnsamples
=
avfilter_get_by_name
(
"asetnsamples"
);
if
(
asetnsamples
==
NULL
)
{
goto
FAIL
;
}
asetnsamples_ctx
=
avfilter_graph_alloc_filter
(
graph
,
asetnsamples
,
"asetnsamples_out"
);
if
(
asetnsamples_ctx
==
NULL
)
{
goto
FAIL
;
}
av_opt_set_int
(
asetnsamples_ctx
,
"n"
,
1152
,
AV_OPT_SEARCH_CHILDREN
);
err
=
avfilter_init_str
(
asetnsamples_ctx
,
NULL
);
if
(
err
<
0
)
{
goto
FAIL
;
}
// Link amix with abuffersink
err
=
avfilter_link
(
amix_ctx
,
0
,
a
buffersink
_ctx
,
0
);
err
=
avfilter_link
(
amix_ctx
,
0
,
a
setnsamples
_ctx
,
0
);
if
(
err
!=
0
)
{
goto
FAIL
;
}
err
=
avfilter_link
(
asetnsamples_ctx
,
0
,
abuffersink_ctx
,
0
);
return
(
FilterChain
){
amix_ctx
,
abuffersink_ctx
};
...
...
@@ -234,12 +427,13 @@ FilterChain build_filter_chain_mix_part(AVFilterGraph *graph, int numOfStreams)
FilterChain
build_filter_chain_shift_part
(
AVFilterGraph
*
graph
,
MixParameters
param
)
{
int
err
=
0
;
char
ch_layout
[
64
]
=
{
0
};
char
filter_name
[
64
]
=
{
0
};
const
AVFilter
*
abuffer
=
NULL
;
AVFilterContext
*
abuffer_ctx
=
NULL
;
const
AVFilter
*
a
setpts
=
NULL
;
AVFilterContext
*
a
setpts
_ctx
=
NULL
;
const
AVFilter
*
a
delay
=
NULL
;
AVFilterContext
*
a
delay
_ctx
=
NULL
;
AVRational
time_base
=
param
.
cc
->
time_base
;
...
...
@@ -248,13 +442,15 @@ FilterChain build_filter_chain_shift_part(AVFilterGraph *graph, MixParameters pa
if
(
abuffer
==
NULL
)
{
goto
FAIL
;
}
abuffer_ctx
=
avfilter_graph_alloc_filter
(
graph
,
abuffer
,
"abuffer"
);
sprintf
(
filter_name
,
"abuffer_%d"
,
param
.
index
);
abuffer_ctx
=
avfilter_graph_alloc_filter
(
graph
,
abuffer
,
filter_name
);
if
(
abuffer_ctx
==
NULL
)
{
goto
FAIL
;
}
av_get_channel_layout_string
(
(
char
*
)
ch_layout
,
sizeof
(
ch_layout
),
0
,
AV_OPT_SEARCH_CHILDREN
);
(
char
*
)
ch_layout
,
sizeof
(
ch_layout
),
0
,
param
.
cc
->
channel_layout
);
av_opt_set
(
abuffer_ctx
,
"channel_layout"
,
(
char
*
)
ch_layout
,
AV_OPT_SEARCH_CHILDREN
);
av_opt_set
(
abuffer_ctx
,
"sample_fmt"
,
av_get_sample_fmt_name
(
param
.
cc
->
sample_fmt
),
...
...
@@ -265,43 +461,43 @@ FilterChain build_filter_chain_shift_part(AVFilterGraph *graph, MixParameters pa
av_opt_set_int
(
abuffer_ctx
,
"sample_rate"
,
param
.
cc
->
sample_rate
,
AV_OPT_SEARCH_CHILDREN
);
err
=
avfilter_init_str
(
abuffer_ctx
,
NULL
);
if
(
err
<
0
)
{
if
(
err
<
0
)
{
;
goto
FAIL
;
}
// Create a
setpts
filter
a
setpts
=
avfilter_get_by_name
(
"asetpts
"
);
if
(
a
setpts
==
NULL
)
{
// Create a
delay
filter
a
delay
=
avfilter_get_by_name
(
"adelay
"
);
if
(
a
delay
==
NULL
)
{
goto
FAIL
;
}
asetpts_ctx
=
avfilter_graph_alloc_filter
(
graph
,
asetpts
,
"asetpts"
);
if
(
asetpts_ctx
==
NULL
)
{
sprintf
(
filter_name
,
"adelay_%d"
,
param
.
index
);
adelay_ctx
=
avfilter_graph_alloc_filter
(
graph
,
adelay
,
filter_name
);
if
(
adelay_ctx
==
NULL
)
{
goto
FAIL
;
}
// Construct expr argument of asetpts
char
expr
[
128
]
=
{
0
};
sprintf
(
expr
,
"PTS+%u/TB"
,
param
.
offset
);
av_opt_set
(
asetpts_ctx
,
"expr"
,
expr
,
AV_OPT_SEARCH_CHILDREN
);
char
delays
[
32
]
=
{
0
};
unsigned
int
offset
=
param
.
offset
*
1000
;
sprintf
(
delays
,
"%d|%d"
,
offset
,
offset
);
av_opt_set
(
adelay_ctx
,
"delays"
,
delays
,
AV_OPT_SEARCH_CHILDREN
);
err
=
avfilter_init_str
(
a
setpts
_ctx
,
NULL
);
err
=
avfilter_init_str
(
a
delay
_ctx
,
NULL
);
if
(
err
<
0
)
{
goto
FAIL
;
}
err
=
avfilter_link
(
abuffer_ctx
,
0
,
a
setpts
_ctx
,
0
);
err
=
avfilter_link
(
abuffer_ctx
,
0
,
a
delay
_ctx
,
0
);
if
(
err
<
0
)
{
goto
FAIL
;
}
return
(
FilterChain
){
abuffer_ctx
,
a
setpts
_ctx
};
return
(
FilterChain
){
abuffer_ctx
,
a
delay
_ctx
};
FAIL:
if
(
abuffer_ctx
)
avfilter_free
(
abuffer_ctx
);
if
(
a
setpts
_ctx
)
avfilter_free
(
a
setpts
_ctx
);
if
(
a
delay
_ctx
)
avfilter_free
(
a
delay
_ctx
);
return
(
FilterChain
){
NULL
,
NULL
};
}
...
...
@@ -356,6 +552,14 @@ AudioStreamingContext* prepare_output_streaming_context(
}
avcodec_parameters_from_context
(
stream
->
codecpar
,
codec_ctx
);
if
(
avio_open
(
&
fmt_ctx
->
pb
,
file
->
filepath
,
AVIO_FLAG_WRITE
)
<
0
)
{
goto
FAIL
;
}
AVDictionary
*
opts
=
NULL
;
if
(
avformat_write_header
(
fmt_ctx
,
NULL
)
<
0
)
{
goto
FAIL
;
}
AudioStreamingContext
*
o_streaming_ctx
=
(
AudioStreamingContext
*
)
malloc
(
sizeof
(
AudioStreamingContext
));
o_streaming_ctx
->
c
=
codec
;
...
...
@@ -440,6 +644,39 @@ AudioStreamingContext* open_audio_file(AudioFile *files) {
int
main
(
int
argc
,
char
*
argv
[])
{
AudioFile
i_file_1
=
{
argv
[
1
],
(
MixParameters
){
0
,
NULL
,
NULL
,
10
}
};
AudioFile
i_file_2
=
{
argv
[
2
],
(
MixParameters
){
1
,
NULL
,
NULL
,
10
}
};
AudioFile
i_file_3
=
{
argv
[
3
],
(
MixParameters
){
2
,
NULL
,
NULL
,
5
}
};
AudioFile
o_file
=
{
argv
[
4
],
(
MixParameters
){
0
,
NULL
,
NULL
,
0
}
};
AudioFile
*
i_files
[
3
]
=
{
&
i_file_1
,
&
i_file_2
,
&
i_file_3
};
audioMixArbitary
(
3
,
i_files
,
&
o_file
);
return
0
;
}
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