avcodec/bsf: Add list BSF API

Signed-off-by: Michael Niedermayer <michael@niedermayer.cc>
This commit is contained in:
Jan Sebechlebsky 2016-08-15 12:38:35 +02:00 committed by Michael Niedermayer
parent 0ea03dbbf9
commit b746ed70ef
3 changed files with 365 additions and 2 deletions

View File

@ -5951,6 +5951,91 @@ void av_bsf_free(AVBSFContext **ctx);
*/
const AVClass *av_bsf_get_class(void);
/**
* Structure for chain/list of bitstream filters.
* Empty list can be allocated by av_bsf_list_alloc().
*/
typedef struct AVBSFList AVBSFList;
/**
* Allocate empty list of bitstream filters.
* The list must be later freed by av_bsf_list_free()
* or finalized by av_bsf_list_finalize().
*
* @return Pointer to @ref AVBSFList on success, NULL in case of failure
*/
AVBSFList *av_bsf_list_alloc(void);
/**
* Free list of bitstream filters.
*
* @param lst Pointer to pointer returned by av_bsf_list_alloc()
*/
void av_bsf_list_free(AVBSFList **lst);
/**
* Append bitstream filter to the list of bitstream filters.
*
* @param lst List to append to
* @param bsf Filter context to be appended
*
* @return >=0 on success, negative AVERROR in case of failure
*/
int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf);
/**
* Construct new bitstream filter context given it's name and options
* and append it to the list of bitstream filters.
*
* @param lst List to append to
* @param bsf_name Name of the bitstream filter
* @param options Options for the bitstream filter, can be set to NULL
*
* @return >=0 on success, negative AVERROR in case of failure
*/
int av_bsf_list_append2(AVBSFList *lst, const char * bsf_name, AVDictionary **options);
/**
* Finalize list of bitstream filters.
*
* This function will transform @ref AVBSFList to single @ref AVBSFContext,
* so the whole chain of bitstream filters can be treated as single filter
* freshly allocated by av_bsf_alloc().
* If the call is successfull, @ref AVBSFList structure is freed and lst
* will be set to NULL. In case of failure, caller is responsible for
* freeing the structure by av_bsf_list_free()
*
* @param lst Filter list structure to be transformed
* @param[out] bsf Pointer to be set to newly created @ref AVBSFContext structure
* representing the chain of bitstream filters
*
* @return >=0 on success, negative AVERROR in case of failure
*/
int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf);
/**
* Parse string describing list of bitstream filters and create single
* @ref AVBSFContext describing the whole chain of bitstream filters.
* Resulting @ref AVBSFContext can be treated as any other @ref AVBSFContext freshly
* allocated by av_bsf_alloc().
*
* @param str String describing chain of bitstream filters in format
* `bsf1[=opt1=val1:opt2=val2][,bsf2]`
* @param[out] bsf Pointer to be set to newly created @ref AVBSFContext structure
* representing the chain of bitstream filters
*
* @return >=0 on success, negative AVERROR in case of failure
*/
int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf);
/**
* Get null/pass-through bitstream filter.
*
* @param[out] bsf Pointer to be set to new instance of pass-through bitstream filter
*
* @return
*/
int av_bsf_get_null_filter(AVBSFContext **bsf);
/* memory */
/**

View File

@ -22,6 +22,8 @@
#include "libavutil/mem.h"
#include "libavutil/opt.h"
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/bprint.h"
#include "avcodec.h"
#include "bsf.h"
@ -236,3 +238,279 @@ int ff_bsf_get_packet_ref(AVBSFContext *ctx, AVPacket *pkt)
return 0;
}
typedef struct BSFListContext {
const AVClass *class;
AVBSFContext **bsfs;
int nb_bsfs;
unsigned idx; // index of currently processed BSF
unsigned flushed_idx; // index of BSF being flushed
} BSFListContext;
static int bsf_list_init(AVBSFContext *bsf)
{
BSFListContext *lst = bsf->priv_data;
int ret, i;
const AVCodecParameters *cod_par = bsf->par_in;
AVRational tb = bsf->time_base_in;
for (i = 0; i < lst->nb_bsfs; ++i) {
ret = avcodec_parameters_copy(lst->bsfs[i]->par_in, cod_par);
if (ret < 0)
goto fail;
lst->bsfs[i]->time_base_in = tb;
ret = av_bsf_init(lst->bsfs[i]);
if (ret < 0)
goto fail;
cod_par = lst->bsfs[i]->par_out;
tb = lst->bsfs[i]->time_base_out;
}
bsf->time_base_out = tb;
ret = avcodec_parameters_copy(bsf->par_out, cod_par);
fail:
return ret;
}
static int bsf_list_filter(AVBSFContext *bsf, AVPacket *out)
{
BSFListContext *lst = bsf->priv_data;
int ret;
if (!lst->nb_bsfs)
return ff_bsf_get_packet_ref(bsf, out);
while (1) {
if (lst->idx > lst->flushed_idx) {
ret = av_bsf_receive_packet(lst->bsfs[lst->idx-1], out);
if (ret == AVERROR(EAGAIN)) {
/* no more packets from idx-1, try with previous */
ret = 0;
lst->idx--;
continue;
} else if (ret == AVERROR_EOF) {
/* filter idx-1 is done, continue with idx...nb_bsfs */
lst->flushed_idx = lst->idx;
continue;
}else if (ret < 0) {
/* filtering error */
break;
}
} else {
ret = ff_bsf_get_packet_ref(bsf, out);
if (ret == AVERROR_EOF) {
lst->idx = lst->flushed_idx;
} else if (ret < 0)
break;
}
if (lst->idx < lst->nb_bsfs) {
AVPacket *pkt;
if (ret == AVERROR_EOF && lst->idx == lst->flushed_idx) {
/* ff_bsf_get_packet_ref returned EOF and idx is first
* filter of yet not flushed filter chain */
pkt = NULL;
} else {
pkt = out;
}
ret = av_bsf_send_packet(lst->bsfs[lst->idx], pkt);
if (ret < 0)
break;
lst->idx++;
} else {
/* The end of filter chain, break to return result */
break;
}
}
if (ret < 0)
av_packet_unref(out);
return ret;
}
static void bsf_list_close(AVBSFContext *bsf)
{
BSFListContext *lst = bsf->priv_data;
int i;
for (i = 0; i < lst->nb_bsfs; ++i)
av_bsf_free(&lst->bsfs[i]);
av_freep(&lst->bsfs);
}
static const AVClass bsf_list_class = {
.class_name = "bsf_list",
.item_name = av_default_item_name,
.version = LIBAVUTIL_VERSION_INT,
};
const AVBitStreamFilter ff_list_bsf = {
.name = "bsf_list",
.priv_data_size = sizeof(BSFListContext),
.priv_class = &bsf_list_class,
.init = bsf_list_init,
.filter = bsf_list_filter,
.close = bsf_list_close,
};
struct AVBSFList {
AVBSFContext **bsfs;
int nb_bsfs;
};
AVBSFList *av_bsf_list_alloc(void)
{
return av_mallocz(sizeof(AVBSFList));
}
void av_bsf_list_free(AVBSFList **lst)
{
int i;
if (*lst)
return;
for (i = 0; i < (*lst)->nb_bsfs; ++i)
av_bsf_free(&(*lst)->bsfs[i]);
av_free((*lst)->bsfs);
av_freep(lst);
}
int av_bsf_list_append(AVBSFList *lst, AVBSFContext *bsf)
{
return av_dynarray_add_nofree(&lst->bsfs, &lst->nb_bsfs, bsf);
}
int av_bsf_list_append2(AVBSFList *lst, const char *bsf_name, AVDictionary ** options)
{
int ret;
const AVBitStreamFilter *filter;
AVBSFContext *bsf;
filter = av_bsf_get_by_name(bsf_name);
if (!filter)
return AVERROR_BSF_NOT_FOUND;
ret = av_bsf_alloc(filter, &bsf);
if (ret < 0)
return ret;
if (options) {
ret = av_opt_set_dict(bsf, options);
if (ret < 0)
goto end;
}
ret = av_bsf_list_append(lst, bsf);
end:
if (ret < 0)
av_bsf_free(&bsf);
return ret;
}
int av_bsf_list_finalize(AVBSFList **lst, AVBSFContext **bsf)
{
int ret = 0;
BSFListContext *ctx;
if ((*lst)->nb_bsfs == 1) {
*bsf = (*lst)->bsfs[0];
av_freep(&(*lst)->bsfs);
(*lst)->nb_bsfs = 0;
goto end;
}
ret = av_bsf_alloc(&ff_list_bsf, bsf);
if (ret < 0)
return ret;
ctx = (*bsf)->priv_data;
ctx->bsfs = (*lst)->bsfs;
ctx->nb_bsfs = (*lst)->nb_bsfs;
end:
av_freep(lst);
return ret;
}
static int bsf_parse_single(const char *str, AVBSFList *bsf_lst)
{
char *bsf_name, *bsf_options_str, *buf;
AVDictionary *bsf_options = NULL;
int ret = 0;
if (!(buf = av_strdup(str)))
return AVERROR(ENOMEM);
bsf_name = av_strtok(buf, "=", &bsf_options_str);
if (!bsf_name) {
ret = AVERROR(EINVAL);
goto end;
}
if (bsf_options_str) {
ret = av_dict_parse_string(&bsf_options, bsf_options_str, "=", ":", 0);
if (ret < 0)
goto end;
}
ret = av_bsf_list_append2(bsf_lst, bsf_name, &bsf_options);
av_dict_free(&bsf_options);
end:
av_free(buf);
return ret;
}
int av_bsf_list_parse_str(const char *str, AVBSFContext **bsf_lst)
{
AVBSFList *lst;
char *bsf_str, *buf, *dup, *saveptr;
int ret;
if (!str)
return av_bsf_get_null_filter(bsf_lst);
lst = av_bsf_list_alloc();
if (!lst)
return AVERROR(ENOMEM);
if (!(dup = buf = av_strdup(str)))
return AVERROR(ENOMEM);
while (1) {
bsf_str = av_strtok(buf, ",", &saveptr);
if (!bsf_str)
break;
ret = bsf_parse_single(bsf_str, lst);
if (ret < 0)
goto end;
buf = NULL;
}
ret = av_bsf_list_finalize(&lst, bsf_lst);
end:
if (ret < 0)
av_bsf_list_free(&lst);
av_free(dup);
return ret;
}
int av_bsf_get_null_filter(AVBSFContext **bsf)
{
return av_bsf_alloc(&ff_list_bsf, bsf);
}

View File

@ -28,8 +28,8 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 57
#define LIBAVCODEC_VERSION_MINOR 51
#define LIBAVCODEC_VERSION_MICRO 102
#define LIBAVCODEC_VERSION_MINOR 52
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \