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