Commit | Line | Data |
---|---|---|
2ba45a60 DM |
1 | /* |
2 | * This file is part of FFmpeg. | |
3 | * | |
4 | * FFmpeg is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU Lesser General Public | |
6 | * License as published by the Free Software Foundation; either | |
7 | * version 2.1 of the License, or (at your option) any later version. | |
8 | * | |
9 | * FFmpeg is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | * Lesser General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU Lesser General Public | |
15 | * License along with FFmpeg; if not, write to the Free Software | |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | ||
19 | /** | |
20 | * @file | |
21 | * replaygain tags parsing | |
22 | */ | |
23 | ||
24 | #include <stdint.h> | |
25 | #include <stdlib.h> | |
26 | #include <string.h> | |
27 | ||
28 | #include "libavutil/avstring.h" | |
29 | #include "libavutil/dict.h" | |
30 | #include "libavutil/intreadwrite.h" | |
31 | #include "libavutil/mathematics.h" | |
32 | #include "libavutil/mem.h" | |
33 | #include "libavutil/replaygain.h" | |
34 | ||
35 | #include "avformat.h" | |
36 | #include "replaygain.h" | |
37 | ||
38 | static int32_t parse_value(const char *value, int32_t min) | |
39 | { | |
40 | char *fraction; | |
41 | int scale = 10000; | |
42 | int32_t mb = 0; | |
43 | int sign = 1; | |
44 | int db; | |
45 | ||
46 | if (!value) | |
47 | return min; | |
48 | ||
49 | value += strspn(value, " \t"); | |
50 | ||
51 | if (*value == '-') | |
52 | sign = -1; | |
53 | ||
54 | db = strtol(value, &fraction, 0); | |
55 | if (*fraction++ == '.') { | |
56 | while (av_isdigit(*fraction) && scale) { | |
57 | mb += scale * (*fraction - '0'); | |
58 | scale /= 10; | |
59 | fraction++; | |
60 | } | |
61 | } | |
62 | ||
63 | if (abs(db) > (INT32_MAX - mb) / 100000) | |
64 | return min; | |
65 | ||
66 | return db * 100000 + sign * mb; | |
67 | } | |
68 | ||
69 | int ff_replaygain_export_raw(AVStream *st, int32_t tg, uint32_t tp, | |
70 | int32_t ag, uint32_t ap) | |
71 | { | |
72 | AVPacketSideData *sd, *tmp; | |
73 | AVReplayGain *replaygain; | |
74 | int i; | |
75 | ||
76 | if (tg == INT32_MIN && ag == INT32_MIN) | |
77 | return 0; | |
78 | ||
79 | for (i = 0; i < st->nb_side_data; i++) { | |
80 | AVPacketSideData *src_sd = &st->side_data[i]; | |
81 | ||
82 | if (src_sd->type == AV_PKT_DATA_REPLAYGAIN) | |
83 | return 0; | |
84 | } | |
85 | ||
86 | replaygain = av_mallocz(sizeof(*replaygain)); | |
87 | if (!replaygain) | |
88 | return AVERROR(ENOMEM); | |
89 | ||
90 | tmp = av_realloc_array(st->side_data, st->nb_side_data + 1, sizeof(*tmp)); | |
91 | if (!tmp) { | |
92 | av_freep(&replaygain); | |
93 | return AVERROR(ENOMEM); | |
94 | } | |
95 | st->side_data = tmp; | |
96 | st->nb_side_data++; | |
97 | ||
98 | sd = &st->side_data[st->nb_side_data - 1]; | |
99 | sd->type = AV_PKT_DATA_REPLAYGAIN; | |
100 | sd->data = (uint8_t*)replaygain; | |
101 | sd->size = sizeof(*replaygain); | |
102 | ||
103 | replaygain->track_gain = tg; | |
104 | replaygain->track_peak = tp; | |
105 | replaygain->album_gain = ag; | |
106 | replaygain->album_peak = ap; | |
107 | ||
108 | return 0; | |
109 | } | |
110 | ||
111 | int ff_replaygain_export(AVStream *st, AVDictionary *metadata) | |
112 | { | |
113 | const AVDictionaryEntry *tg, *tp, *ag, *ap; | |
114 | ||
115 | tg = av_dict_get(metadata, "REPLAYGAIN_TRACK_GAIN", NULL, 0); | |
116 | tp = av_dict_get(metadata, "REPLAYGAIN_TRACK_PEAK", NULL, 0); | |
117 | ag = av_dict_get(metadata, "REPLAYGAIN_ALBUM_GAIN", NULL, 0); | |
118 | ap = av_dict_get(metadata, "REPLAYGAIN_ALBUM_PEAK", NULL, 0); | |
119 | ||
120 | return ff_replaygain_export_raw(st, | |
121 | parse_value(tg ? tg->value : NULL, INT32_MIN), | |
122 | parse_value(tp ? tp->value : NULL, 0), | |
123 | parse_value(ag ? ag->value : NULL, INT32_MIN), | |
124 | parse_value(ap ? ap->value : NULL, 0)); | |
125 | } |