aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Niedermayer <michaelni@gmx.at>2014-04-29 19:29:44 +0200
committerMichael Niedermayer <michaelni@gmx.at>2014-04-29 19:29:48 +0200
commit03b88f6b393359957ac9f7f0fb9b148ab51b3da5 (patch)
tree9da2548d45816813308362cccb712a674f98715f
parent4506ed336ff74ea0cafbb01edbb44821815a60a4 (diff)
parent41334fcab41fee1a5a869c9f87c4a1d59a627b57 (diff)
downloadffmpeg-03b88f6b393359957ac9f7f0fb9b148ab51b3da5.tar.gz
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: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r--doc/APIchanges6
-rw-r--r--doc/demuxers.texi8
-rw-r--r--doc/filters.texi9
-rw-r--r--ffprobe.c7
-rw-r--r--libavcodec/avcodec.h8
-rw-r--r--libavcodec/codec_desc.c152
-rw-r--r--libavcodec/version.h4
-rw-r--r--libavfilter/vf_drawtext.c37
-rw-r--r--libavformat/concatdec.c207
-rw-r--r--libavformat/matroska.c1
-rw-r--r--libavutil/hash.c35
-rw-r--r--libavutil/hash.h22
-rw-r--r--libavutil/version.h2
-rw-r--r--tools/ffhash.c34
-rwxr-xr-xtools/missing_codec_desc1
15 files changed, 471 insertions, 62 deletions
diff --git a/doc/APIchanges b/doc/APIchanges
index 8fe5ff2e7c..a35501a2bd 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -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.
diff --git a/doc/demuxers.texi b/doc/demuxers.texi
index 23cec5a386..d51b9d0748 100644
--- a/doc/demuxers.texi
+++ b/doc/demuxers.texi
@@ -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
diff --git a/doc/filters.texi b/doc/filters.texi
index e943923e00..a8b2668889 100644
--- a/doc/filters.texi
+++ b/doc/filters.texi
@@ -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
diff --git a/ffprobe.c b/ffprobe.c
index 319bbc65c8..c6e0469d18 100644
--- a/ffprobe.c
+++ b/ffprobe.c
@@ -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) {
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 9a14e6654a..1d42bbe0fa 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -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;
/**
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 8785e3a810..4906a0a21d 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -26,6 +26,8 @@
#include "avcodec.h"
#include "version.h"
+#define MT(...) (const char *const[]){ __VA_ARGS__, NULL }
+
static const AVCodecDescriptor codec_descriptors[] = {
/* video codecs */
{
@@ -85,6 +87,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "mjpeg",
.long_name = NULL_IF_CONFIG_SMALL("Motion JPEG"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+ .mime_types= MT("image/jpeg"),
},
{
.id = AV_CODEC_ID_MJPEGB,
@@ -526,6 +529,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "bmp",
.long_name = NULL_IF_CONFIG_SMALL("BMP (Windows and OS/2 bitmap)"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/x-ms-bmp"),
},
{
.id = AV_CODEC_ID_CSCD,
@@ -597,6 +601,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("JPEG 2000"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY |
AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/jp2"),
},
{
.id = AV_CODEC_ID_VMNC,
@@ -1277,6 +1282,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "gif",
.long_name = NULL_IF_CONFIG_SMALL("GIF (Graphics Interchange Format)"),
.props = AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/gif"),
},
{
.id = AV_CODEC_ID_JPEGLS,
@@ -1299,6 +1305,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "pam",
.long_name = NULL_IF_CONFIG_SMALL("PAM (Portable AnyMap) image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/x-portable-pixmap"),
},
{
.id = AV_CODEC_ID_PBM,
@@ -1313,6 +1320,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "pcx",
.long_name = NULL_IF_CONFIG_SMALL("PC Paintbrush PCX image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/x-pcx"),
},
{
.id = AV_CODEC_ID_PGM,
@@ -1334,6 +1342,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "png",
.long_name = NULL_IF_CONFIG_SMALL("PNG (Portable Network Graphics) image"),
.props = AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/png"),
},
{
.id = AV_CODEC_ID_PPM,
@@ -1376,6 +1385,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "targa",
.long_name = NULL_IF_CONFIG_SMALL("Truevision Targa image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/x-targa", "image/x-tga"),
},
{
.id = AV_CODEC_ID_TIFF,
@@ -1383,6 +1393,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "tiff",
.long_name = NULL_IF_CONFIG_SMALL("TIFF image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/tiff"),
},
{
.id = AV_CODEC_ID_TXD,
@@ -1405,6 +1416,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("WebP"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY |
AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/webp"),
},
{
.id = AV_CODEC_ID_WMV3IMAGE,
@@ -1426,6 +1438,7 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "xwd",
.long_name = NULL_IF_CONFIG_SMALL("XWD (X Window Dump) image"),
.props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ .mime_types= MT("image/x-xwindowdump"),
},
/* various PCM "codecs" */
@@ -2649,6 +2662,15 @@ static const AVCodecDescriptor codec_descriptors[] = {
.long_name = NULL_IF_CONFIG_SMALL("WebVTT subtitle"),
.props = AV_CODEC_PROP_TEXT_SUB,
},
+
+ /* other kind of codecs and pseudo-codecs */
+ {
+ .id = AV_CODEC_ID_TTF,
+ .type = AVMEDIA_TYPE_DATA,
+ .name = "ttf",
+ .long_name = NULL_IF_CONFIG_SMALL("TrueType font"),
+ .mime_types= MT("application/x-truetype-font", "application/x-font"),
+ },
{
.id = AV_CODEC_ID_BINTEXT,
.type = AVMEDIA_TYPE_VIDEO,
@@ -2671,6 +2693,13 @@ static const AVCodecDescriptor codec_descriptors[] = {
.props = AV_CODEC_PROP_INTRA_ONLY,
},
{
+ .id = AV_CODEC_ID_OTF,
+ .type = AVMEDIA_TYPE_DATA,
+ .name = "otf",
+ .long_name = NULL_IF_CONFIG_SMALL("OpenType font"),
+ .mime_types= MT("application/vnd.ms-opentype"),
+ },
+ {
.id = AV_CODEC_ID_SMPTE_KLV,
.type = AVMEDIA_TYPE_DATA,
.name = "klv",
@@ -2688,7 +2717,130 @@ static const AVCodecDescriptor codec_descriptors[] = {
.name = "timed_id3",
.long_name = NULL_IF_CONFIG_SMALL("timed ID3 metadata"),
},
+ {
+ .id = AV_CODEC_ID_BIN_DATA,
+ .type = AVMEDIA_TYPE_DATA,
+ .name = "bin_data",
+ .long_name = NULL_IF_CONFIG_SMALL("binary data"),
+ .mime_types= MT("application/octet-stream"),
+ },
+
+ /* deprecated codec ids */
+ {
+ .id = AV_CODEC_ID_BRENDER_PIX_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "brender_pix_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("BRender PIX image (deprecated id)"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_ESCAPE130_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "escape130_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("Escape 130 (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_EXR_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "exr_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("OpenEXR image (deprecated id)"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY |
+ AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_G2M_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "g2m_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("Go2Meeting (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_HEVC_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "hevc_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("H.265 / HEVC (High Efficiency Video Coding) (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_PAF_VIDEO_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "paf_video_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Video (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_SANM_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "sanm_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts SANM/SMUSH video (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_VP7_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "vp7_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("On2 VP7 (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_WEBP_DEPRECATED,
+ .type = AVMEDIA_TYPE_VIDEO,
+ .name = "webp_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("WebP (deprecated id)"),
+ .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY |
+ AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_VIMA,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "vima",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_ADPCM_VIMA_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "adpcm_vima_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("LucasArts VIMA audio (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_OPUS_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "opus_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("Opus (Opus Interactive Audio Codec) (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_PAF_AUDIO_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "paf_audio_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("Amazing Studio Packed Animation File Audio (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSY,
+ },
+ {
+ .id = AV_CODEC_ID_PCM_S24LE_PLANAR_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "pcm_s24le_planar_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("PCM signed 24-bit little-endian planar (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_PCM_S32LE_PLANAR_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "pcm_s32le_planar_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("PCM signed 32-bit little-endian planar (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSLESS,
+ },
+ {
+ .id = AV_CODEC_ID_TAK_DEPRECATED,
+ .type = AVMEDIA_TYPE_AUDIO,
+ .name = "tak_deprecated",
+ .long_name = NULL_IF_CONFIG_SMALL("TAK (Tom's lossless Audio Kompressor) (deprecated id)"),
+ .props = AV_CODEC_PROP_LOSSLESS,
+ },
};
const AVCodecDescriptor *avcodec_descriptor_get(enum AVCodecID id)
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 43a4cc4946..44ec052198 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -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, \
diff --git a/libavfilter/vf_drawtext.c b/libavfilter/vf_drawtext.c
index f7486c9c6e..995a3e2ca3 100644
--- a/libavfilter/vf_drawtext.c
+++ b/libavfilter/vf_drawtext.c
@@ -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 },
diff --git a/libavformat/concatdec.c b/libavformat/concatdec.c
index c79bee54e2..4590dc5923 100644
--- a/libavformat/concatdec.c
+++ b/libavformat/concatdec.c
@@ -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 }
};
diff --git a/libavformat/matroska.c b/libavformat/matroska.c
index 77a88a8756..e8e99967db 100644
--- a/libavformat/matroska.c
+++ b/libavformat/matroska.c
@@ -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}
};
diff --git a/libavutil/hash.c b/libavutil/hash.c
index a8cf80b577..773f29e23b 100644
--- a/libavutil/hash.c
+++ b/libavutil/hash.c
@@ -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)
diff --git a/libavutil/hash.h b/libavutil/hash.h
index 9bf715e1ac..d4bcbf8cc8 100644
--- a/libavutil/hash.h
+++ b/libavutil/hash.h
@@ -83,6 +83,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.
*/
void av_hash_freep(struct AVHashContext **ctx);
diff --git a/libavutil/version.h b/libavutil/version.h
index edafa30a3f..a17cb506de 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -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, \
diff --git a/tools/ffhash.c b/tools/ffhash.c
index 086d48a7ab..a9f71c26c5 100644
--- a/tools/ffhash.c
+++ b/tools/ffhash.c
@@ -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;
}
diff --git a/tools/missing_codec_desc b/tools/missing_codec_desc
index 093d02e02e..e1d3d60b4f 100755
--- a/tools/missing_codec_desc
+++ b/tools/missing_codec_desc
@@ -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