Commit 03b88f6b authored by Michael Niedermayer's avatar Michael Niedermayer

Merge remote-tracking branch 'cigaes/master'

* cigaes/master:
  lavfi/drawtext: allow to format pts as HH:MM:SS.mmm.
  lavf/concatdec: implement automatic conversions.
  lavf/concatdec: reindent after last commit.
  lavf/concatdec: always do stream matching.
  lavf/concatdec: check match_streams() return value.
  lavf/concatdec: use a structure for each stream.
  ffprobe: use the codec descriptor if no decoder was found.
  lavf/matroska: add "binary" pseudo-MIME type.
  lavc: minor bump and APIchanges for AVCodecDescriptor.mime_types.
  lavc: add a mime_types field to codec descriptors.
  lavc: add AV_CODEC_ID_BIN_DATA.
  lavc: add codec descriptors for TTF and OTF.
  lavc: add codec descriptors for deprecated ids.
  lavc/codec_desc: add separation comment.
  tools/ffhash: implement base64 output.
  tools/ffhash: use av_hash_final_hex().
  lavu/hash: add hash_final helpers.
Merged-by: 's avatarMichael Niedermayer <michaelni@gmx.at>
parents 4506ed33 41334fca
......@@ -15,6 +15,12 @@ libavutil: 2012-10-22
API changes, most recent first:
2014-04-29 - 1bf6396 - lavc 55.60.100 - avcodec.h
Add AVCodecDescriptor.mime_types field.
2014-04-29 - xxxxxxx - lavu 52.80.0 - hash.h
Add av_hash_final_bin(), av_hash_final_hex() and av_hash_final_b64().
2014-03-07 - 8b2a130 - lavc 55.50.0 / 55.53.100 - dxva2.h
Add FF_DXVA2_WORKAROUND_INTEL_CLEARVIDEO for old Intel GPUs.
......
......@@ -128,6 +128,14 @@ If set to 0, any file name is accepted.
The default is -1, it is equivalent to 1 if the format was automatically
probed and 0 otherwise.
@item auto_convert
If set to 1, try to perform automatic conversions on packet data to make the
streams concatenable.
Currently, the only conversion is adding the h264_mp4toannexb bitstream
filter to H.264 streams in MP4 format. This is necessary in particular if
there are resolution changes.
@end table
@section flv
......
......@@ -3850,7 +3850,14 @@ The frame number, starting from 0.
A 1 character description of the current picture type.
@item pts
The timestamp of the current frame, in seconds, with microsecond accuracy.
The timestamp of the current frame.
It can take up to two arguments.
The first argument is the format of the timestamp; it defaults to @code{flt}
for seconds as a decimal number with microsecond accuracy; @code{hms} stands
for a formatted @var{[-]HH:MM:SS.mmm} timestamp with millisecond accuracy.
The second argument is an offset added to the timestamp.
@end table
......
......@@ -1976,6 +1976,7 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id
const char *s;
AVRational sar, dar;
AVBPrint pbuf;
const AVCodecDescriptor *cd;
int ret = 0;
av_bprint_init(&pbuf, 1, AV_BPRINT_SIZE_UNLIMITED);
......@@ -1993,6 +1994,12 @@ static int show_stream(WriterContext *w, AVFormatContext *fmt_ctx, int stream_id
if (dec->long_name) print_str ("codec_long_name", dec->long_name);
else print_str_opt("codec_long_name", "unknown");
}
} else if ((cd = avcodec_descriptor_get(stream->codec->codec_id))) {
print_str_opt("codec_name", cd->name);
if (!do_bitexact) {
print_str_opt("codec_long_name",
cd->long_name ? cd->long_name : "unknown");
}
} else {
print_str_opt("codec_name", "unknown");
if (!do_bitexact) {
......
......@@ -533,6 +533,7 @@ enum AVCodecID {
AV_CODEC_ID_SMPTE_KLV = MKBETAG('K','L','V','A'),
AV_CODEC_ID_DVD_NAV = MKBETAG('D','N','A','V'),
AV_CODEC_ID_TIMED_ID3 = MKBETAG('T','I','D','3'),
AV_CODEC_ID_BIN_DATA = MKBETAG('D','A','T','A'),
AV_CODEC_ID_PROBE = 0x19000, ///< codec_id is not known (like AV_CODEC_ID_NONE) but lavf should attempt to identify it
......@@ -570,6 +571,13 @@ typedef struct AVCodecDescriptor {
* Codec properties, a combination of AV_CODEC_PROP_* flags.
*/
int props;
/**
* MIME type(s) associated with the codec.
* May be NULL; if not, a NULL-terminated array of MIME types.
* The first item is always non-NULL and is the prefered MIME type.
*/
const char *const *mime_types;
} AVCodecDescriptor;
/**
......
This diff is collapsed.
......@@ -29,8 +29,8 @@
#include "libavutil/version.h"
#define LIBAVCODEC_VERSION_MAJOR 55
#define LIBAVCODEC_VERSION_MINOR 59
#define LIBAVCODEC_VERSION_MICRO 101
#define LIBAVCODEC_VERSION_MINOR 60
#define LIBAVCODEC_VERSION_MICRO 100
#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
LIBAVCODEC_VERSION_MINOR, \
......
......@@ -699,8 +699,41 @@ static int func_pts(AVFilterContext *ctx, AVBPrint *bp,
char *fct, unsigned argc, char **argv, int tag)
{
DrawTextContext *s = ctx->priv;
const char *fmt;
double pts = s->var_values[VAR_T];
int ret;
av_bprintf(bp, "%.6f", s->var_values[VAR_T]);
fmt = argc >= 1 ? argv[0] : "flt";
if (argc >= 2) {
int64_t delta;
if ((ret = av_parse_time(&delta, argv[1], 1)) < 0) {
av_log(ctx, AV_LOG_ERROR, "Invalid delta '%s'\n", argv[1]);
return ret;
}
pts += (double)delta / AV_TIME_BASE;
}
if (!strcmp(fmt, "flt")) {
av_bprintf(bp, "%.6f", s->var_values[VAR_T]);
} else if (!strcmp(fmt, "hms")) {
if (isnan(pts)) {
av_bprintf(bp, " ??:??:??.???");
} else {
int64_t ms = round(pts * 1000);
char sign = ' ';
if (ms < 0) {
sign = '-';
ms = -ms;
}
av_bprintf(bp, "%c%02d:%02d:%02d.%03d", sign,
(int)(ms / (60 * 60 * 1000)),
(int)(ms / (60 * 1000)) % 60,
(int)(ms / 1000) % 60,
(int)ms % 1000);
}
} else {
av_log(ctx, AV_LOG_ERROR, "Invalid format '%s'\n", fmt);
return AVERROR(EINVAL);
}
return 0;
}
......@@ -776,7 +809,7 @@ static const struct drawtext_function {
{ "expr", 1, 1, 0, func_eval_expr },
{ "e", 1, 1, 0, func_eval_expr },
{ "pict_type", 0, 0, 0, func_pict_type },
{ "pts", 0, 0, 0, func_pts },
{ "pts", 0, 2, 0, func_pts },
{ "gmtime", 0, 1, 'G', func_strftime },
{ "localtime", 0, 1, 'L', func_strftime },
{ "frame_num", 0, 0, 0, func_frame_num },
......
......@@ -18,19 +18,31 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/avassert.h"
#include "libavutil/avstring.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/opt.h"
#include "libavutil/parseutils.h"
#include "avformat.h"
#include "internal.h"
#include "url.h"
typedef enum ConcatMatchMode {
MATCH_ONE_TO_ONE,
MATCH_EXACT_ID,
} ConcatMatchMode;
typedef struct ConcatStream {
AVBitStreamFilterContext *bsf;
int out_stream_index;
} ConcatStream;
typedef struct {
char *url;
int64_t start_time;
int64_t duration;
int *stream_map;
int stream_map_size;
ConcatStream *streams;
int nb_streams;
} ConcatFile;
typedef struct {
......@@ -41,7 +53,8 @@ typedef struct {
AVFormatContext *avf;
int safe;
int seekable;
int match_streams;
ConcatMatchMode stream_match_mode;
unsigned auto_convert;
} ConcatContext;
static int concat_probe(AVProbeData *probe)
......@@ -141,6 +154,17 @@ static int copy_stream_props(AVStream *st, AVStream *source_st)
{
int ret;
if (st->codec->codec_id || !source_st->codec->codec_id) {
if (st->codec->extradata_size < source_st->codec->extradata_size) {
ret = ff_alloc_extradata(st->codec,
source_st->codec->extradata_size);
if (ret < 0)
return ret;
}
memcpy(st->codec->extradata, source_st->codec->extradata,
source_st->codec->extradata_size);
return 0;
}
if ((ret = avcodec_copy_context(st->codec, source_st->codec)) < 0)
return ret;
st->r_frame_rate = source_st->r_frame_rate;
......@@ -150,38 +174,103 @@ static int copy_stream_props(AVStream *st, AVStream *source_st)
return 0;
}
static int match_streams(AVFormatContext *avf)
static int detect_stream_specific(AVFormatContext *avf, int idx)
{
ConcatContext *cat = avf->priv_data;
AVStream *st = cat->avf->streams[idx];
ConcatStream *cs = &cat->cur_file->streams[idx];
AVBitStreamFilterContext *bsf;
if (cat->auto_convert && st->codec->codec_id == AV_CODEC_ID_H264 &&
(st->codec->extradata_size < 4 || AV_RB32(st->codec->extradata) != 1)) {
av_log(cat->avf, AV_LOG_INFO,
"Auto-inserting h264_mp4toannexb bitstream filter\n");
if (!(bsf = av_bitstream_filter_init("h264_mp4toannexb"))) {
av_log(avf, AV_LOG_ERROR, "h264_mp4toannexb bitstream filter "
"required for H.264 streams\n");
return AVERROR_BSF_NOT_FOUND;
}
cs->bsf = bsf;
}
return 0;
}
static int match_streams_one_to_one(AVFormatContext *avf)
{
ConcatContext *cat = avf->priv_data;
AVStream *st;
int *map, i, j, ret;
int i, ret;
if (!cat->match_streams ||
cat->cur_file->stream_map_size >= cat->avf->nb_streams)
return 0;
map = av_realloc(cat->cur_file->stream_map,
cat->avf->nb_streams * sizeof(*map));
if (!map)
return AVERROR(ENOMEM);
cat->cur_file->stream_map = map;
for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
if (i < avf->nb_streams) {
st = avf->streams[i];
} else {
if (!(st = avformat_new_stream(avf, NULL)))
return AVERROR(ENOMEM);
}
if ((ret = copy_stream_props(st, cat->avf->streams[i])) < 0)
return ret;
cat->cur_file->streams[i].out_stream_index = i;
}
return 0;
}
static int match_streams_exact_id(AVFormatContext *avf)
{
ConcatContext *cat = avf->priv_data;
AVStream *st;
int i, j, ret;
for (i = cat->cur_file->stream_map_size; i < cat->avf->nb_streams; i++) {
for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++) {
st = cat->avf->streams[i];
map[i] = -1;
for (j = 0; j < avf->nb_streams; j++) {
if (avf->streams[j]->id == st->id) {
av_log(avf, AV_LOG_VERBOSE,
"Match slave stream #%d with stream #%d id 0x%x\n",
i, j, st->id);
map[i] = j;
if (!avf->streams[j]->codec->codec_id && st->codec->codec_id)
if ((ret = copy_stream_props(avf->streams[j], st)) < 0)
return ret;
if ((ret = copy_stream_props(avf->streams[j], st)) < 0)
return ret;
cat->cur_file->streams[i].out_stream_index = j;
}
}
}
return 0;
}
cat->cur_file->stream_map_size = cat->avf->nb_streams;
static int match_streams(AVFormatContext *avf)
{
ConcatContext *cat = avf->priv_data;
ConcatStream *map;
int i, ret;
if (cat->cur_file->nb_streams >= cat->avf->nb_streams)
return 0;
map = av_realloc(cat->cur_file->streams,
cat->avf->nb_streams * sizeof(*map));
if (!map)
return AVERROR(ENOMEM);
cat->cur_file->streams = map;
memset(map + cat->cur_file->nb_streams, 0,
(cat->avf->nb_streams - cat->cur_file->nb_streams) * sizeof(*map));
for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++)
map[i].out_stream_index = -1;
switch (cat->stream_match_mode) {
case MATCH_ONE_TO_ONE:
ret = match_streams_one_to_one(avf);
break;
case MATCH_EXACT_ID:
ret = match_streams_exact_id(avf);
break;
default:
ret = AVERROR_BUG;
}
if (ret < 0)
return ret;
for (i = cat->cur_file->nb_streams; i < cat->avf->nb_streams; i++)
if ((ret = detect_stream_specific(avf, i)) < 0)
return ret;
cat->cur_file->nb_streams = cat->avf->nb_streams;
return 0;
}
......@@ -222,8 +311,10 @@ static int concat_read_close(AVFormatContext *avf)
if (cat->avf)
avformat_close_input(&cat->avf);
for (i = 0; i < cat->nb_files; i++)
for (i = 0; i < cat->nb_files; i++) {
av_freep(&cat->files[i].url);
av_freep(&cat->files[i].streams);
}
av_freep(&cat->files);
return 0;
}
......@@ -236,7 +327,6 @@ static int concat_read_header(AVFormatContext *avf)
int ret, line = 0, i;
unsigned nb_files_alloc = 0;
ConcatFile *file = NULL;
AVStream *st;
int64_t time = 0;
while (1) {
......@@ -315,18 +405,10 @@ static int concat_read_header(AVFormatContext *avf)
cat->seekable = 1;
}
cat->match_streams = !!avf->nb_streams;
cat->stream_match_mode = avf->nb_streams ? MATCH_EXACT_ID :
MATCH_ONE_TO_ONE;
if ((ret = open_file(avf, 0)) < 0)
FAIL(ret);
if (!cat->match_streams) {
for (i = 0; i < cat->avf->nb_streams; i++) {
if (!(st = avformat_new_stream(avf, NULL)))
FAIL(AVERROR(ENOMEM));
if ((ret = copy_stream_props(st, cat->avf->streams[i])) < 0)
FAIL(ret);
}
}
return 0;
fail:
......@@ -347,11 +429,52 @@ static int open_next_file(AVFormatContext *avf)
return open_file(avf, fileno);
}
static int filter_packet(AVFormatContext *avf, ConcatStream *cs, AVPacket *pkt)
{
AVStream *st = avf->streams[cs->out_stream_index];
AVBitStreamFilterContext *bsf;
AVPacket pkt2;
int ret;
av_assert0(cs->out_stream_index >= 0);
for (bsf = cs->bsf; bsf; bsf = bsf->next) {
pkt2 = *pkt;
ret = av_bitstream_filter_filter(bsf, st->codec, NULL,
&pkt2.data, &pkt2.size,
pkt->data, pkt->size,
!!(pkt->flags & AV_PKT_FLAG_KEY));
if (ret < 0) {
av_packet_unref(pkt);
return ret;
}
av_assert0(pkt2.buf);
if (ret == 0 && pkt2.data != pkt->data) {
if ((ret = av_copy_packet(&pkt2, pkt)) < 0) {
av_free(pkt2.data);
return ret;
}
ret = 1;
}
if (ret > 0) {
av_free_packet(pkt);
pkt2.buf = av_buffer_create(pkt2.data, pkt2.size,
av_buffer_default_free, NULL, 0);
if (!pkt2.buf) {
av_free(pkt2.data);
return AVERROR(ENOMEM);
}
}
*pkt = pkt2;
}
return 0;
}
static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
{
ConcatContext *cat = avf->priv_data;
int ret;
int64_t delta;
ConcatStream *cs;
while (1) {
ret = av_read_frame(cat->avf, pkt);
......@@ -362,16 +485,20 @@ static int concat_read_packet(AVFormatContext *avf, AVPacket *pkt)
}
if (ret < 0)
return ret;
if (cat->match_streams) {
match_streams(avf);
pkt->stream_index = cat->cur_file->stream_map[pkt->stream_index];
if (pkt->stream_index < 0) {
av_packet_unref(pkt);
continue;
}
if ((ret = match_streams(avf)) < 0) {
av_packet_unref(pkt);
return ret;
}
cs = &cat->cur_file->streams[pkt->stream_index];
if (cs->out_stream_index < 0) {
av_packet_unref(pkt);
continue;
}
pkt->stream_index = cs->out_stream_index;
break;
}
if ((ret = filter_packet(avf, cs, pkt)))
return ret;
delta = av_rescale_q(cat->cur_file->start_time - cat->avf->start_time,
AV_TIME_BASE_Q,
......@@ -478,6 +605,8 @@ static int concat_seek(AVFormatContext *avf, int stream,
static const AVOption options[] = {
{ "safe", "enable safe mode",
OFFSET(safe), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 1, DEC },
{ "auto_convert", "automatically convert bitstream format",
OFFSET(auto_convert), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 1, DEC },
{ NULL }
};
......
......@@ -113,6 +113,7 @@ const CodecMime ff_mkv_mime_tags[] = {
{"application/x-truetype-font", AV_CODEC_ID_TTF},
{"application/x-font" , AV_CODEC_ID_TTF},
{"application/vnd.ms-opentype", AV_CODEC_ID_OTF},
{"binary" , AV_CODEC_ID_BIN_DATA},
{"" , AV_CODEC_ID_NONE}
};
......
......@@ -29,6 +29,7 @@
#include "sha512.h"
#include "avstring.h"
#include "base64.h"
#include "error.h"
#include "intreadwrite.h"
#include "mem.h"
......@@ -196,6 +197,40 @@ void av_hash_final(AVHashContext *ctx, uint8_t *dst)
}
}
void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size)
{
uint8_t buf[AV_HASH_MAX_SIZE];
unsigned rsize = av_hash_get_size(ctx);
av_hash_final(ctx, buf);
memcpy(dst, buf, FFMIN(size, rsize));
if (size > rsize)
memset(dst + rsize, 0, size - rsize);
}
void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size)
{
uint8_t buf[AV_HASH_MAX_SIZE];
unsigned rsize = av_hash_get_size(ctx), i;
av_hash_final(ctx, buf);
for (i = 0; i < FFMIN(rsize, size / 2); i++)
snprintf(dst + i * 2, size - i * 2, "%02x", buf[i]);
}
void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size)
{
uint8_t buf[AV_HASH_MAX_SIZE], b64[AV_BASE64_SIZE(AV_HASH_MAX_SIZE)];
unsigned rsize = av_hash_get_size(ctx), osize;
av_hash_final(ctx, buf);
av_base64_encode(b64, sizeof(b64), buf, rsize);
osize = AV_BASE64_SIZE(rsize);
memcpy(dst, b64, FFMIN(osize, size));
if (size < osize)
dst[size - 1] = 0;
}
void av_hash_freep(AVHashContext **ctx)
{
if (*ctx)
......
......@@ -82,6 +82,28 @@ void av_hash_update(struct AVHashContext *ctx, const uint8_t *src, int len);
*/
void av_hash_final(struct AVHashContext *ctx, uint8_t *dst);
/**
* Finalize a hash context and compute the actual hash value.
* If size is smaller than the hash size, the hash is truncated;
* if size is larger, the buffer is padded with 0.
*/
void av_hash_final_bin(struct AVHashContext *ctx, uint8_t *dst, int size);
/**
* Finalize a hash context and compute the actual hash value as a hex string.
* The string is always 0-terminated.
* If size is smaller than 2 * hash_size + 1, the hex string is truncated.
*/
void av_hash_final_hex(struct AVHashContext *ctx, uint8_t *dst, int size);
/**
* Finalize a hash context and compute the actual hash value as a base64 string.
* The string is always 0-terminated.
* If size is smaller than AV_BASE64_SIZE(hash_size), the base64 string is
* truncated.
*/
void av_hash_final_b64(struct AVHashContext *ctx, uint8_t *dst, int size);
/**
* Free hash context.
*/
......
......@@ -56,7 +56,7 @@
*/
#define LIBAVUTIL_VERSION_MAJOR 52
#define LIBAVUTIL_VERSION_MINOR 79
#define LIBAVUTIL_VERSION_MINOR 80
#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
......
......@@ -21,6 +21,7 @@
*/
#include "config.h"
#include "libavutil/avstring.h"
#include "libavutil/error.h"
#include "libavutil/hash.h"
#include "libavutil/mem.h"
......@@ -40,14 +41,14 @@
#define SIZE 65536
static struct AVHashContext *hash;
static uint8_t *res;
static int out_b64;
static void usage(void)
{
int i = 0;
const char *name;
printf("usage: ffhash [algorithm] [input]...\n");
printf("usage: ffhash [b64:]algorithm [input]...\n");
printf("Supported hash algorithms:");
do {
name = av_hash_names(i);
......@@ -60,12 +61,16 @@ static void usage(void)
static void finish(void)
{
int i, len = av_hash_get_size(hash);
printf("%s=0x", av_hash_get_name(hash));
av_hash_final(hash, res);
for (i = 0; i < len; i++)
printf("%02x", res[i]);
char res[2 * AV_HASH_MAX_SIZE + 4];
printf("%s=", av_hash_get_name(hash));
if (out_b64) {
av_hash_final_b64(hash, res, sizeof(res));
printf("b64:%s", res);
} else {
av_hash_final_hex(hash, res, sizeof(res));
printf("0x%s", res);
}
}
static int check(char *file)
......@@ -113,16 +118,19 @@ int main(int argc, char **argv)
{
int i;
int ret = 0;
const char *hash_name;
if (argc == 1) {
usage();
return 0;
}
if ((ret = av_hash_alloc(&hash, argv[1])) < 0) {
hash_name = argv[1];
out_b64 = av_strstart(hash_name, "b64:", &hash_name);
if ((ret = av_hash_alloc(&hash, hash_name)) < 0) {
switch(ret) {
case AVERROR(EINVAL):
printf("Invalid hash type: %s\n", argv[1]);
printf("Invalid hash type: %s\n", hash_name);
break;
case AVERROR(ENOMEM):
printf("%s\n", strerror(errno));
......@@ -130,11 +138,6 @@ int main(int argc, char **argv)
}
return 1;
}
res = av_malloc(av_hash_get_size(hash));
if (!res) {
printf("%s\n", strerror(errno));
return 1;
}
for (i = 2; i < argc; i++)
ret |= check(argv[i]);
......@@ -143,7 +146,6 @@ int main(int argc, char **argv)
ret |= check(NULL);
av_hash_freep(&hash);
av_freep(&res);
return ret;
}
......@@ -14,7 +14,6 @@ known_AV_CODEC_ID_NONE=1
known_AV_CODEC_ID_FIRST_AUDIO=1
known_AV_CODEC_ID_FIRST_SUBTITLE=1
known_AV_CODEC_ID_FIRST_UNKNOWN=1
known_AV_CODEC_ID_TTF=1
known_AV_CODEC_ID_PROBE=1
known_AV_CODEC_ID_MPEG2TS=1
known_AV_CODEC_ID_MPEG4SYSTEMS=1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment