FFmpeg
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
Examples
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
libavformat
icoenc.c
Go to the documentation of this file.
1
/*
2
* Microsoft Windows ICO muxer
3
* Copyright (c) 2012 Michael Bradshaw <mjbshaw gmail com>
4
*
5
* This file is part of FFmpeg.
6
*
7
* FFmpeg is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
11
*
12
* FFmpeg is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
16
*
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with FFmpeg; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20
*/
21
22
/**
23
* @file
24
* Microsoft Windows ICO muxer
25
*/
26
27
#include "
libavutil/intreadwrite.h
"
28
#include "
libavutil/pixdesc.h
"
29
#include "
avformat.h
"
30
31
typedef
struct
{
32
int
offset
;
33
int
size
;
34
unsigned
char
width
;
35
unsigned
char
height
;
36
short
bits
;
37
}
IcoImage
;
38
39
typedef
struct
{
40
int
current_image
;
41
int
nb_images
;
42
IcoImage
*
images
;
43
}
IcoMuxContext
;
44
45
static
int
ico_check_attributes
(
AVFormatContext
*
s
,
const
AVCodecContext
*
c
)
46
{
47
if
(c->
codec_id
==
AV_CODEC_ID_BMP
) {
48
if
(c->
pix_fmt
==
AV_PIX_FMT_PAL8
&&
AV_PIX_FMT_RGB32
!=
AV_PIX_FMT_BGRA
) {
49
av_log
(s,
AV_LOG_ERROR
,
"Wrong endianness for bmp pixel format\n"
);
50
return
AVERROR
(EINVAL);
51
}
else
if
(c->
pix_fmt
!=
AV_PIX_FMT_PAL8
&&
52
c->
pix_fmt
!=
AV_PIX_FMT_RGB555LE
&&
53
c->
pix_fmt
!=
AV_PIX_FMT_BGR24
&&
54
c->
pix_fmt
!=
AV_PIX_FMT_BGRA
) {
55
av_log
(s,
AV_LOG_ERROR
,
"BMP must be 1bit, 4bit, 8bit, 16bit, 24bit, or 32bit\n"
);
56
return
AVERROR
(EINVAL);
57
}
58
}
else
if
(c->
codec_id
==
AV_CODEC_ID_PNG
) {
59
if
(c->
pix_fmt
!=
AV_PIX_FMT_RGBA
) {
60
av_log
(s,
AV_LOG_ERROR
,
"PNG in ico requires pixel format to be rgba\n"
);
61
return
AVERROR
(EINVAL);
62
}
63
}
else
{
64
av_log
(s,
AV_LOG_ERROR
,
"Unsupported codec %s\n"
, c->
codec_name
);
65
return
AVERROR
(EINVAL);
66
}
67
68
if
(c->
width
> 256 ||
69
c->
height
> 256) {
70
av_log
(s,
AV_LOG_ERROR
,
"Unsupported dimensions %dx%d (dimensions cannot exceed 256x256)\n"
, c->
width
, c->
height
);
71
return
AVERROR
(EINVAL);
72
}
73
74
return
0;
75
}
76
77
static
int
ico_write_header
(
AVFormatContext
*
s
)
78
{
79
IcoMuxContext
*ico = s->
priv_data
;
80
AVIOContext
*pb = s->
pb
;
81
int
ret
;
82
int
i;
83
84
if
(!pb->
seekable
) {
85
av_log
(s,
AV_LOG_ERROR
,
"Output is not seekable\n"
);
86
return
AVERROR
(EINVAL);
87
}
88
89
ico->
current_image
= 0;
90
ico->
nb_images
= s->
nb_streams
;
91
92
avio_wl16
(pb, 0);
// reserved
93
avio_wl16
(pb, 1);
// 1 == icon
94
avio_skip
(pb, 2);
// skip the number of images
95
96
for
(i = 0; i < s->
nb_streams
; i++) {
97
if
(ret =
ico_check_attributes
(s, s->
streams
[i]->
codec
))
98
return
ret
;
99
100
// Fill in later when writing trailer...
101
avio_skip
(pb, 16);
102
}
103
104
ico->
images
=
av_mallocz_array
(ico->
nb_images
,
sizeof
(
IcoMuxContext
));
105
if
(!ico->
images
)
106
return
AVERROR
(ENOMEM);
107
108
avio_flush
(pb);
109
110
return
0;
111
}
112
113
static
int
ico_write_packet
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
114
{
115
IcoMuxContext
*ico = s->
priv_data
;
116
IcoImage
*image;
117
AVIOContext
*pb = s->
pb
;
118
AVCodecContext
*
c
= s->
streams
[pkt->
stream_index
]->
codec
;
119
int
i;
120
121
if
(ico->
current_image
>= ico->
nb_images
) {
122
av_log
(s,
AV_LOG_ERROR
,
"ICO already contains %d images\n"
, ico->
current_image
);
123
return
AVERROR
(EIO);
124
}
125
126
image = &ico->
images
[ico->
current_image
++];
127
128
image->
offset
=
avio_tell
(pb);
129
image->
width
= (c->
width
== 256) ? 0 : c->
width
;
130
image->
height
= (c->
height
== 256) ? 0 : c->
height
;
131
132
if
(c->
codec_id
==
AV_CODEC_ID_PNG
) {
133
image->
bits
= c->
bits_per_coded_sample
;
134
image->
size
= pkt->
size
;
135
136
avio_write
(pb, pkt->
data
, pkt->
size
);
137
}
else
{
// BMP
138
if
(
AV_RL32
(pkt->
data
+ 14) != 40) {
// must be BITMAPINFOHEADER
139
av_log
(s,
AV_LOG_ERROR
,
"Invalid BMP\n"
);
140
return
AVERROR
(EINVAL);
141
}
142
143
image->
bits
=
AV_RL16
(pkt->
data
+ 28);
// allows things like 1bit and 4bit images to be preserved
144
image->
size
= pkt->
size
- 14 + c->
height
* (c->
width
+ 7) / 8;
145
146
avio_write
(pb, pkt->
data
+ 14, 8);
// Skip the BITMAPFILEHEADER header
147
avio_wl32
(pb,
AV_RL32
(pkt->
data
+ 22) * 2);
// rewrite height as 2 * height
148
avio_write
(pb, pkt->
data
+ 26, pkt->
size
- 26);
149
150
for
(i = 0; i < c->
height
* (c->
width
+ 7) / 8; ++i)
151
avio_w8
(pb, 0x00);
// Write bitmask (opaque)
152
}
153
154
return
0;
155
}
156
157
static
int
ico_write_trailer
(
AVFormatContext
*
s
)
158
{
159
IcoMuxContext
*ico = s->
priv_data
;
160
AVIOContext
*pb = s->
pb
;
161
int
i;
162
163
avio_seek
(pb, 4, SEEK_SET);
164
165
avio_wl16
(pb, ico->
current_image
);
166
167
for
(i = 0; i < ico->
nb_images
; i++) {
168
avio_w8
(pb, ico->
images
[i].
width
);
169
avio_w8
(pb, ico->
images
[i].
height
);
170
171
if
(s->
streams
[i]->
codec
->
codec_id
==
AV_CODEC_ID_BMP
&&
172
s->
streams
[i]->
codec
->
pix_fmt
==
AV_PIX_FMT_PAL8
) {
173
avio_w8
(pb, (ico->
images
[i].
bits
>= 8) ? 0 : 1 << ico->
images
[i].
bits
);
174
}
else
{
175
avio_w8
(pb, 0);
176
}
177
178
avio_w8
(pb, 0);
// reserved
179
avio_wl16
(pb, 1);
// color planes
180
avio_wl16
(pb, ico->
images
[i].
bits
);
181
avio_wl32
(pb, ico->
images
[i].
size
);
182
avio_wl32
(pb, ico->
images
[i].
offset
);
183
}
184
185
av_freep
(&ico->
images
);
186
187
return
0;
188
}
189
190
AVOutputFormat
ff_ico_muxer
= {
191
.
name
=
"ico"
,
192
.long_name =
NULL_IF_CONFIG_SMALL
(
"Microsoft Windows ICO"
),
193
.priv_data_size =
sizeof
(
IcoMuxContext
),
194
.mime_type =
"image/vnd.microsoft.icon"
,
195
.extensions =
"ico"
,
196
.audio_codec =
AV_CODEC_ID_NONE
,
197
.video_codec =
AV_CODEC_ID_BMP
,
198
.
write_header
=
ico_write_header
,
199
.
write_packet
=
ico_write_packet
,
200
.
write_trailer
=
ico_write_trailer
,
201
.
flags
=
AVFMT_NOTIMESTAMPS
,
202
};
Generated on Sun Jul 20 2014 23:06:03 for FFmpeg by
1.8.2