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
const
AVCodecDescriptor
*codesc =
avcodec_descriptor_get
(c->
codec_id
);
65
av_log
(s,
AV_LOG_ERROR
,
"Unsupported codec %s\n"
, codesc ? codesc->
name
:
""
);
66
return
AVERROR
(EINVAL);
67
}
68
69
if
(c->
width
> 256 ||
70
c->
height
> 256) {
71
av_log
(s,
AV_LOG_ERROR
,
"Unsupported dimensions %dx%d (dimensions cannot exceed 256x256)\n"
, c->
width
, c->
height
);
72
return
AVERROR
(EINVAL);
73
}
74
75
return
0;
76
}
77
78
static
int
ico_write_header
(
AVFormatContext
*
s
)
79
{
80
IcoMuxContext
*ico = s->
priv_data
;
81
AVIOContext
*pb = s->
pb
;
82
int
ret
;
83
int
i;
84
85
if
(!pb->
seekable
) {
86
av_log
(s,
AV_LOG_ERROR
,
"Output is not seekable\n"
);
87
return
AVERROR
(EINVAL);
88
}
89
90
ico->
current_image
= 0;
91
ico->
nb_images
= s->
nb_streams
;
92
93
avio_wl16
(pb, 0);
// reserved
94
avio_wl16
(pb, 1);
// 1 == icon
95
avio_skip
(pb, 2);
// skip the number of images
96
97
for
(i = 0; i < s->
nb_streams
; i++) {
98
if
(ret =
ico_check_attributes
(s, s->
streams
[i]->
codec
))
99
return
ret
;
100
101
// Fill in later when writing trailer...
102
avio_skip
(pb, 16);
103
}
104
105
ico->
images
=
av_mallocz_array
(ico->
nb_images
,
sizeof
(
IcoMuxContext
));
106
if
(!ico->
images
)
107
return
AVERROR
(ENOMEM);
108
109
avio_flush
(pb);
110
111
return
0;
112
}
113
114
static
int
ico_write_packet
(
AVFormatContext
*
s
,
AVPacket
*
pkt
)
115
{
116
IcoMuxContext
*ico = s->
priv_data
;
117
IcoImage
*image;
118
AVIOContext
*pb = s->
pb
;
119
AVCodecContext
*
c
= s->
streams
[pkt->
stream_index
]->
codec
;
120
int
i;
121
122
if
(ico->
current_image
>= ico->
nb_images
) {
123
av_log
(s,
AV_LOG_ERROR
,
"ICO already contains %d images\n"
, ico->
current_image
);
124
return
AVERROR
(EIO);
125
}
126
127
image = &ico->
images
[ico->
current_image
++];
128
129
image->
offset
=
avio_tell
(pb);
130
image->
width
= (c->
width
== 256) ? 0 : c->
width
;
131
image->
height
= (c->
height
== 256) ? 0 : c->
height
;
132
133
if
(c->
codec_id
==
AV_CODEC_ID_PNG
) {
134
image->
bits
= c->
bits_per_coded_sample
;
135
image->
size
= pkt->
size
;
136
137
avio_write
(pb, pkt->
data
, pkt->
size
);
138
}
else
{
// BMP
139
if
(
AV_RL32
(pkt->
data
+ 14) != 40) {
// must be BITMAPINFOHEADER
140
av_log
(s,
AV_LOG_ERROR
,
"Invalid BMP\n"
);
141
return
AVERROR
(EINVAL);
142
}
143
144
image->
bits
=
AV_RL16
(pkt->
data
+ 28);
// allows things like 1bit and 4bit images to be preserved
145
image->
size
= pkt->
size
- 14 + c->
height
* (c->
width
+ 7) / 8;
146
147
avio_write
(pb, pkt->
data
+ 14, 8);
// Skip the BITMAPFILEHEADER header
148
avio_wl32
(pb,
AV_RL32
(pkt->
data
+ 22) * 2);
// rewrite height as 2 * height
149
avio_write
(pb, pkt->
data
+ 26, pkt->
size
- 26);
150
151
for
(i = 0; i < c->
height
* (c->
width
+ 7) / 8; ++i)
152
avio_w8
(pb, 0x00);
// Write bitmask (opaque)
153
}
154
155
return
0;
156
}
157
158
static
int
ico_write_trailer
(
AVFormatContext
*
s
)
159
{
160
IcoMuxContext
*ico = s->
priv_data
;
161
AVIOContext
*pb = s->
pb
;
162
int
i;
163
164
avio_seek
(pb, 4, SEEK_SET);
165
166
avio_wl16
(pb, ico->
current_image
);
167
168
for
(i = 0; i < ico->
nb_images
; i++) {
169
avio_w8
(pb, ico->
images
[i].
width
);
170
avio_w8
(pb, ico->
images
[i].
height
);
171
172
if
(s->
streams
[i]->
codec
->
codec_id
==
AV_CODEC_ID_BMP
&&
173
s->
streams
[i]->
codec
->
pix_fmt
==
AV_PIX_FMT_PAL8
) {
174
avio_w8
(pb, (ico->
images
[i].
bits
>= 8) ? 0 : 1 << ico->
images
[i].
bits
);
175
}
else
{
176
avio_w8
(pb, 0);
177
}
178
179
avio_w8
(pb, 0);
// reserved
180
avio_wl16
(pb, 1);
// color planes
181
avio_wl16
(pb, ico->
images
[i].
bits
);
182
avio_wl32
(pb, ico->
images
[i].
size
);
183
avio_wl32
(pb, ico->
images
[i].
offset
);
184
}
185
186
av_freep
(&ico->
images
);
187
188
return
0;
189
}
190
191
AVOutputFormat
ff_ico_muxer
= {
192
.
name
=
"ico"
,
193
.long_name =
NULL_IF_CONFIG_SMALL
(
"Microsoft Windows ICO"
),
194
.priv_data_size =
sizeof
(
IcoMuxContext
),
195
.mime_type =
"image/vnd.microsoft.icon"
,
196
.extensions =
"ico"
,
197
.audio_codec =
AV_CODEC_ID_NONE
,
198
.video_codec =
AV_CODEC_ID_BMP
,
199
.
write_header
=
ico_write_header
,
200
.
write_packet
=
ico_write_packet
,
201
.
write_trailer
=
ico_write_trailer
,
202
.
flags
=
AVFMT_NOTIMESTAMPS
,
203
};
Generated on Sun Sep 14 2014 18:56:12 for FFmpeg by
1.8.2