Commit | Line | Data |
---|---|---|
f20dca40 FB |
1 | /* |
2 | * Raw DV format | |
3 | * Copyright (c) 2002 Fabrice Bellard. | |
4 | * | |
5 | * This library is free software; you can redistribute it and/or | |
6 | * modify it under the terms of the GNU Lesser General Public | |
7 | * License as published by the Free Software Foundation; either | |
8 | * version 2 of the License, or (at your option) any later version. | |
9 | * | |
10 | * This library is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | * Lesser General Public License for more details. | |
14 | * | |
15 | * You should have received a copy of the GNU Lesser General Public | |
16 | * License along with this library; if not, write to the Free Software | |
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | */ | |
19 | #include "avformat.h" | |
118e91f3 | 20 | #include "dvcore.h" |
f20dca40 FB |
21 | |
22 | typedef struct DVDemuxContext { | |
425ed6e2 | 23 | int is_audio; |
118e91f3 | 24 | uint8_t buf[144000]; |
425ed6e2 | 25 | int size; |
f20dca40 FB |
26 | } DVDemuxContext; |
27 | ||
28 | /* raw input */ | |
29 | static int dv_read_header(AVFormatContext *s, | |
30 | AVFormatParameters *ap) | |
31 | { | |
425ed6e2 FB |
32 | AVStream *vst, *ast; |
33 | DVDemuxContext *c = s->priv_data; | |
f20dca40 FB |
34 | |
35 | vst = av_new_stream(s, 0); | |
36 | if (!vst) | |
37 | return AVERROR_NOMEM; | |
38 | vst->codec.codec_type = CODEC_TYPE_VIDEO; | |
39 | vst->codec.codec_id = CODEC_ID_DVVIDEO; | |
118e91f3 | 40 | vst->codec.bit_rate = 25000000; |
425ed6e2 | 41 | |
f20dca40 FB |
42 | ast = av_new_stream(s, 1); |
43 | if (!ast) | |
44 | return AVERROR_NOMEM; | |
45 | ||
46 | ast->codec.codec_type = CODEC_TYPE_AUDIO; | |
47 | ast->codec.codec_id = CODEC_ID_DVAUDIO; | |
425ed6e2 FB |
48 | c->is_audio = 0; |
49 | ||
f20dca40 FB |
50 | return 0; |
51 | } | |
52 | ||
ec820113 FB |
53 | static void __destruct_pkt(struct AVPacket *pkt) |
54 | { | |
55 | pkt->data = NULL; pkt->size = 0; | |
56 | return; | |
57 | } | |
58 | ||
c18a2692 | 59 | static int dv_read_packet(AVFormatContext *s, AVPacket *pkt) |
f20dca40 | 60 | { |
118e91f3 | 61 | int ret; |
425ed6e2 | 62 | DVDemuxContext *c = s->priv_data; |
f20dca40 | 63 | |
425ed6e2 FB |
64 | if (!c->is_audio) { |
65 | ret = get_buffer(&s->pb, c->buf, 4); | |
66 | if (ret <= 0) | |
67 | return -EIO; | |
118e91f3 | 68 | c->size = dv_frame_profile(&c->buf[0])->frame_size; |
425ed6e2 FB |
69 | |
70 | ret = get_buffer(&s->pb, c->buf + 4, c->size - 4); | |
71 | if (ret <= 0) | |
72 | return -EIO; | |
73 | } | |
f20dca40 | 74 | |
ec820113 FB |
75 | av_init_packet(pkt); |
76 | pkt->destruct = __destruct_pkt; | |
77 | pkt->data = c->buf; | |
78 | pkt->size = c->size; | |
425ed6e2 | 79 | pkt->stream_index = c->is_audio; |
e738cee9 | 80 | pkt->flags |= PKT_FLAG_KEY; |
ec820113 | 81 | |
425ed6e2 | 82 | c->is_audio = !c->is_audio; |
ec820113 | 83 | return c->size; |
f20dca40 FB |
84 | } |
85 | ||
c18a2692 | 86 | static int dv_read_close(AVFormatContext *s) |
f20dca40 FB |
87 | { |
88 | return 0; | |
89 | } | |
90 | ||
f20dca40 FB |
91 | int dv_write_header(struct AVFormatContext *s) |
92 | { | |
118e91f3 RS |
93 | DVMuxContext *c = s->priv_data; |
94 | ||
95 | if (s->nb_streams != 2 || dv_core_init(c, s->streams) != 0) { | |
96 | fprintf(stderr, "Can't initialize DV format!\n" | |
97 | "Make sure that you supply exactly two streams:\n" | |
98 | " video: 25fps or 29.97fps, audio: 2ch/48Khz/PCM\n"); | |
99 | return -1; | |
100 | } | |
f20dca40 FB |
101 | return 0; |
102 | } | |
103 | ||
104 | int dv_write_packet(struct AVFormatContext *s, | |
49057904 FB |
105 | int stream_index, |
106 | const uint8_t *buf, int size, int64_t pts) | |
f20dca40 | 107 | { |
118e91f3 RS |
108 | DVMuxContext *c = s->priv_data; |
109 | ||
110 | if (stream_index == c->vst) | |
111 | dv_assemble_frame(c, buf, NULL, 0); | |
112 | else | |
113 | dv_assemble_frame(c, NULL, buf, size); | |
114 | ||
115 | if (c->has_audio && c->has_video) { | |
116 | put_buffer(&s->pb, &c->frame_buf[0], c->sys->frame_size); | |
117 | put_flush_packet(&s->pb); | |
118 | } | |
119 | ||
f20dca40 FB |
120 | return 0; |
121 | } | |
122 | ||
118e91f3 RS |
123 | /* |
124 | * We might end up with some extra A/V data without matching counterpart. | |
125 | * E.g. video data without enough audio to write the complete frame. | |
126 | * Currently we simply drop the last frame. I don't know whether this | |
127 | * is the best strategy of all | |
128 | */ | |
f20dca40 FB |
129 | int dv_write_trailer(struct AVFormatContext *s) |
130 | { | |
118e91f3 | 131 | dv_core_delete((DVMuxContext *)s->priv_data); |
f20dca40 FB |
132 | return 0; |
133 | } | |
134 | ||
118e91f3 RS |
135 | static AVInputFormat dv_iformat = { |
136 | "dv", | |
137 | "DV video format", | |
138 | sizeof(DVDemuxContext), | |
139 | NULL, | |
140 | dv_read_header, | |
141 | dv_read_packet, | |
142 | dv_read_close, | |
143 | .extensions = "dv", | |
144 | }; | |
145 | ||
f20dca40 FB |
146 | AVOutputFormat dv_oformat = { |
147 | "dv", | |
148 | "DV video format", | |
149 | NULL, | |
150 | "dv", | |
118e91f3 RS |
151 | sizeof(DVMuxContext), |
152 | CODEC_ID_PCM_S16LE, | |
f20dca40 | 153 | CODEC_ID_DVVIDEO, |
f20dca40 FB |
154 | dv_write_header, |
155 | dv_write_packet, | |
156 | dv_write_trailer, | |
157 | }; | |
f20dca40 FB |
158 | |
159 | int dv_init(void) | |
160 | { | |
161 | av_register_input_format(&dv_iformat); | |
3e2937be | 162 | av_register_output_format(&dv_oformat); |
f20dca40 FB |
163 | return 0; |
164 | } |