| 1 | /* |
| 2 | * Copyright (c) 2013 Nicolas George |
| 3 | * |
| 4 | * This file is part of FFmpeg. |
| 5 | * |
| 6 | * FFmpeg is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU Lesser General Public License |
| 8 | * as published by the Free Software Foundation; either |
| 9 | * version 2.1 of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * FFmpeg is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU Lesser General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU Lesser General Public License |
| 17 | * along with FFmpeg; if not, write to the Free Software Foundation, Inc., |
| 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 19 | */ |
| 20 | |
| 21 | #include "libavutil/adler32.h" |
| 22 | #include "libavutil/avassert.h" |
| 23 | #include "libavutil/bprint.h" |
| 24 | #include "libavutil/imgutils.h" |
| 25 | #include "libavutil/pixdesc.h" |
| 26 | #include "avformat.h" |
| 27 | #include "internal.h" |
| 28 | |
| 29 | /* Identical to Adler32 when the type is uint8_t. */ |
| 30 | #define DEFINE_CKSUM_LINE(name, type, conv) \ |
| 31 | static void cksum_line_ ## name(unsigned *cksum, void *data, unsigned size) \ |
| 32 | { \ |
| 33 | type *p = data; \ |
| 34 | unsigned a = *cksum & 0xFFFF, b = *cksum >> 16; \ |
| 35 | for (; size > 0; size--, p++) { \ |
| 36 | a = (a + (unsigned)(conv)) % 65521; \ |
| 37 | b = (b + a) % 65521; \ |
| 38 | } \ |
| 39 | *cksum = a | (b << 16); \ |
| 40 | } |
| 41 | |
| 42 | DEFINE_CKSUM_LINE(u8, uint8_t, *p) |
| 43 | DEFINE_CKSUM_LINE(s16, int16_t, *p + 0x8000) |
| 44 | DEFINE_CKSUM_LINE(s32, int32_t, *p + 0x80000000) |
| 45 | DEFINE_CKSUM_LINE(flt, float, *p * 0x80000000 + 0x80000000) |
| 46 | DEFINE_CKSUM_LINE(dbl, double, *p * 0x80000000 + 0x80000000) |
| 47 | |
| 48 | static void video_frame_cksum(AVBPrint *bp, AVFrame *frame) |
| 49 | { |
| 50 | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(frame->format); |
| 51 | int i, y; |
| 52 | uint8_t *data; |
| 53 | int linesize[5] = { 0 }; |
| 54 | |
| 55 | av_bprintf(bp, ", %d x %d", frame->width, frame->height); |
| 56 | if (!desc) { |
| 57 | av_bprintf(bp, ", unknown"); |
| 58 | return; |
| 59 | } |
| 60 | if (av_image_fill_linesizes(linesize, frame->format, frame->width) < 0) |
| 61 | return; |
| 62 | av_bprintf(bp, ", %s", desc->name); |
| 63 | for (i = 0; linesize[i]; i++) { |
| 64 | unsigned cksum = 0; |
| 65 | int h = frame->height; |
| 66 | if ((i == 1 || i == 2) && desc->nb_components >= 3) |
| 67 | h = -((-h) >> desc->log2_chroma_h); |
| 68 | data = frame->data[i]; |
| 69 | for (y = 0; y < h; y++) { |
| 70 | cksum = av_adler32_update(cksum, data, linesize[i]); |
| 71 | data += frame->linesize[i]; |
| 72 | } |
| 73 | av_bprintf(bp, ", 0x%08x", cksum); |
| 74 | } |
| 75 | } |
| 76 | |
| 77 | static void audio_frame_cksum(AVBPrint *bp, AVFrame *frame) |
| 78 | { |
| 79 | int nb_planes, nb_samples, p; |
| 80 | const char *name; |
| 81 | |
| 82 | nb_planes = av_frame_get_channels(frame); |
| 83 | nb_samples = frame->nb_samples; |
| 84 | if (!av_sample_fmt_is_planar(frame->format)) { |
| 85 | nb_samples *= nb_planes; |
| 86 | nb_planes = 1; |
| 87 | } |
| 88 | name = av_get_sample_fmt_name(frame->format); |
| 89 | av_bprintf(bp, ", %d samples", frame->nb_samples); |
| 90 | av_bprintf(bp, ", %s", name ? name : "unknown"); |
| 91 | for (p = 0; p < nb_planes; p++) { |
| 92 | uint32_t cksum = 0; |
| 93 | void *d = frame->extended_data[p]; |
| 94 | switch (frame->format) { |
| 95 | case AV_SAMPLE_FMT_U8: |
| 96 | case AV_SAMPLE_FMT_U8P: |
| 97 | cksum_line_u8(&cksum, d, nb_samples); |
| 98 | break; |
| 99 | case AV_SAMPLE_FMT_S16: |
| 100 | case AV_SAMPLE_FMT_S16P: |
| 101 | cksum_line_s16(&cksum, d, nb_samples); |
| 102 | break; |
| 103 | case AV_SAMPLE_FMT_S32: |
| 104 | case AV_SAMPLE_FMT_S32P: |
| 105 | cksum_line_s32(&cksum, d, nb_samples); |
| 106 | break; |
| 107 | case AV_SAMPLE_FMT_FLT: |
| 108 | case AV_SAMPLE_FMT_FLTP: |
| 109 | cksum_line_flt(&cksum, d, nb_samples); |
| 110 | break; |
| 111 | case AV_SAMPLE_FMT_DBL: |
| 112 | case AV_SAMPLE_FMT_DBLP: |
| 113 | cksum_line_dbl(&cksum, d, nb_samples); |
| 114 | break; |
| 115 | default: |
| 116 | av_assert0(!"reached"); |
| 117 | } |
| 118 | av_bprintf(bp, ", 0x%08x", cksum); |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | static int write_frame(struct AVFormatContext *s, int stream_index, |
| 123 | AVFrame **frame, unsigned flags) |
| 124 | { |
| 125 | AVBPrint bp; |
| 126 | int ret = 0; |
| 127 | enum AVMediaType type; |
| 128 | const char *type_name; |
| 129 | |
| 130 | if ((flags & AV_WRITE_UNCODED_FRAME_QUERY)) |
| 131 | return 0; |
| 132 | |
| 133 | av_bprint_init(&bp, 0, AV_BPRINT_SIZE_UNLIMITED); |
| 134 | av_bprintf(&bp, "%d, %10"PRId64"", |
| 135 | stream_index, (*frame)->pts); |
| 136 | type = s->streams[stream_index]->codec->codec_type; |
| 137 | type_name = av_get_media_type_string(type); |
| 138 | av_bprintf(&bp, ", %s", type_name ? type_name : "unknown"); |
| 139 | switch (type) { |
| 140 | case AVMEDIA_TYPE_VIDEO: |
| 141 | video_frame_cksum(&bp, *frame); |
| 142 | break; |
| 143 | case AVMEDIA_TYPE_AUDIO: |
| 144 | audio_frame_cksum(&bp, *frame); |
| 145 | break; |
| 146 | } |
| 147 | |
| 148 | av_bprint_chars(&bp, '\n', 1); |
| 149 | if (av_bprint_is_complete(&bp)) |
| 150 | avio_write(s->pb, bp.str, bp.len); |
| 151 | else |
| 152 | ret = AVERROR(ENOMEM); |
| 153 | av_bprint_finalize(&bp, NULL); |
| 154 | return ret; |
| 155 | } |
| 156 | |
| 157 | static int write_packet(struct AVFormatContext *s, AVPacket *pkt) |
| 158 | { |
| 159 | return AVERROR(ENOSYS); |
| 160 | } |
| 161 | |
| 162 | AVOutputFormat ff_uncodedframecrc_muxer = { |
| 163 | .name = "uncodedframecrc", |
| 164 | .long_name = NULL_IF_CONFIG_SMALL("uncoded framecrc testing"), |
| 165 | .audio_codec = AV_CODEC_ID_PCM_S16LE, |
| 166 | .video_codec = AV_CODEC_ID_RAWVIDEO, |
| 167 | .write_header = ff_framehash_write_header, |
| 168 | .write_packet = write_packet, |
| 169 | .write_uncoded_frame = write_frame, |
| 170 | .flags = AVFMT_VARIABLE_FPS | AVFMT_TS_NONSTRICT | |
| 171 | AVFMT_TS_NEGATIVE, |
| 172 | }; |