diff --git a/libavformat/Makefile b/libavformat/Makefile index 72ef8c7c44..ff98b9b29f 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -388,6 +388,7 @@ OBJS-$(CONFIG_TRUEHD_MUXER) += rawenc.o OBJS-$(CONFIG_TTA_DEMUXER) += tta.o apetag.o img2.o OBJS-$(CONFIG_TTY_DEMUXER) += tty.o sauce.o OBJS-$(CONFIG_TXD_DEMUXER) += txd.o +OBJS-$(CONFIG_UNCODEDFRAMECRC_MUXER) += uncodedframecrcenc.o framehash.o OBJS-$(CONFIG_VC1_DEMUXER) += rawdec.o OBJS-$(CONFIG_VC1_MUXER) += rawenc.o OBJS-$(CONFIG_VC1T_DEMUXER) += vc1test.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 195e6fb168..6ee2f99e5b 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -284,6 +284,7 @@ void av_register_all(void) REGISTER_DEMUXER (TTA, tta); REGISTER_DEMUXER (TXD, txd); REGISTER_DEMUXER (TTY, tty); + REGISTER_MUXER (UNCODEDFRAMECRC, uncodedframecrc); REGISTER_MUXDEMUX(VC1, vc1); REGISTER_MUXDEMUX(VC1T, vc1t); REGISTER_DEMUXER (VIVO, vivo); diff --git a/libavformat/uncodedframecrcenc.c b/libavformat/uncodedframecrcenc.c new file mode 100644 index 0000000000..414683fe23 --- /dev/null +++ b/libavformat/uncodedframecrcenc.c @@ -0,0 +1,172 @@ +/* +* Copyright (c) 2013 Nicolas George +* +* This file is part of FFmpeg. +* +* FFmpeg is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public License +* as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* FFmpeg is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with FFmpeg; if not, write to the Free Software Foundation, Inc., +* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "libavutil/adler32.h" +#include "libavutil/avassert.h" +#include "libavutil/bprint.h" +#include "libavutil/imgutils.h" +#include "libavutil/pixdesc.h" +#include "avformat.h" +#include "internal.h" + +/* Identical to Adler32 when the type is uint8_t. */ +#define DEFINE_CKSUM_LINE(name, type, conv) \ +static void cksum_line_ ## name(unsigned *cksum, void *data, unsigned size) \ +{ \ + type *p = data; \ + unsigned a = *cksum & 0xFFFF, b = *cksum >> 16; \ + for (; size > 0; size--, p++) { \ + a = (a + (unsigned)(conv)) % 65521; \ + b = (b + a) % 65521; \ + } \ + *cksum = a | (b << 16); \ +} + +DEFINE_CKSUM_LINE(u8, uint8_t, *p) +DEFINE_CKSUM_LINE(s16, int16_t, *p + 0x8000) +DEFINE_CKSUM_LINE(s32, int32_t, *p + 0x80000000) +DEFINE_CKSUM_LINE(flt, float, *p * 0x80000000 + 0x80000000) +DEFINE_CKSUM_LINE(dbl, double, *p * 0x80000000 + 0x80000000) + +static void video_frame_cksum(AVBPrint *bp, AVFrame *frame) +{ + const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); + int i, y; + uint8_t *data; + int linesize[5] = { 0 }; + + av_bprintf(bp, ", %d x %d", frame->width, frame->height); + if (!desc) { + av_bprintf(bp, ", unknown"); + return; + } + if (av_image_fill_linesizes(linesize, frame->format, frame->width) < 0) + return; + av_bprintf(bp, ", %s", desc->name); + for (i = 0; linesize[i]; i++) { + unsigned cksum = 0; + int h = frame->height; + if ((i == 1 || i == 2) && desc->nb_components >= 3) + h = -((-h) >> desc->log2_chroma_h); + data = frame->data[i]; + for (y = 0; y < h; y++) { + cksum = av_adler32_update(cksum, data, linesize[i]); + data += frame->linesize[i]; + } + av_bprintf(bp, ", 0x%08x", cksum); + } +} + +static void audio_frame_cksum(AVBPrint *bp, AVFrame *frame) +{ + int nb_planes, nb_samples, p; + const char *name; + + nb_planes = av_frame_get_channels(frame); + nb_samples = frame->nb_samples; + if (!av_sample_fmt_is_planar(frame->format)) { + nb_samples *= nb_planes; + nb_planes = 1; + } + name = av_get_sample_fmt_name(frame->format); + av_bprintf(bp, ", %d samples", frame->nb_samples); + av_bprintf(bp, ", %s", name ? name : "unknown"); + for (p = 0; p < nb_planes; p++) { + uint32_t cksum = 0; + void *d = frame->extended_data[p]; + switch (frame->format) { + case AV_SAMPLE_FMT_U8: + case AV_SAMPLE_FMT_U8P: + cksum_line_u8(&cksum, d, nb_samples); + break; + case AV_SAMPLE_FMT_S16: + case AV_SAMPLE_FMT_S16P: + cksum_line_s16(&cksum, d, nb_samples); + break; + case AV_SAMPLE_FMT_S32: + case AV_SAMPLE_FMT_S32P: + cksum_line_s32(&cksum, d, nb_samples); + break; + case AV_SAMPLE_FMT_FLT: + case AV_SAMPLE_FMT_FLTP: + cksum_line_flt(&cksum, d, nb_samples); + break; + case AV_SAMPLE_FMT_DBL: + case AV_SAMPLE_FMT_DBLP: + cksum_line_dbl(&cksum, d, nb_samples); + break; + default: + av_assert0(!"reached"); + } + av_bprintf(bp, ", 0x%08x", cksum); + } +} + +static int write_frame(struct AVFormatContext *s, int stream_index, + AVFrame **frame, unsigned flags) +{ + AVBPrint bp; + int ret = 0; + enum AVMediaType type; + const char *type_name; + + if ((flags & AV_WRITE_UNCODED_FRAME_QUERY)) + return 0; + + av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); + av_bprintf(&bp, "%d, %10"PRId64"", + stream_index, (*frame)->pts); + type = s->streams[stream_index]->codec->codec_type; + type_name = av_get_media_type_string(type); + av_bprintf(&bp, ", %s", type_name ? type_name : "unknown"); + switch (type) { + case AVMEDIA_TYPE_VIDEO: + video_frame_cksum(&bp, *frame); + break; + case AVMEDIA_TYPE_AUDIO: + audio_frame_cksum(&bp, *frame); + break; + } + + av_bprint_chars(&bp, '\n', 1); + if (av_bprint_is_complete(&bp)) + avio_write(s->pb, bp.str, bp.len); + else + ret = AVERROR(ENOMEM); + av_bprint_finalize(&bp, NULL); + return ret; +} + +static int write_packet(struct AVFormatContext *s, AVPacket *pkt) +{ + return AVERROR(ENOSYS); +} + +AVOutputFormat ff_uncodedframecrc_muxer = { + .name = "uncodedframecrc", + .long_name = NULL_IF_CONFIG_SMALL("uncoded framecrc testing"), + .audio_codec = AV_CODEC_ID_PCM_S16LE, + .video_codec = AV_CODEC_ID_RAWVIDEO, + .write_header = ff_framehash_write_header, + .write_packet = write_packet, + .write_uncoded_frame = write_frame, + .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | + AVFMT_TS_NEGATIVE, +};