streamers / out-stream-avf.c @ 7a86f98f
History | View | Annotate | Download (4.07 KB)
1 | 21ec2f15 | Luca Abeni | /*
|
---|---|---|---|
2 | * Copyright (c) 2010 Luca Abeni
|
||
3 | *
|
||
4 | * This is free software; see gpl-3.0.txt
|
||
5 | */
|
||
6 | |||
7 | d74bb0e5 | Luca Abeni | #include <libavformat/avformat.h> |
8 | #include <stdio.h> |
||
9 | |||
10 | #include "out-stream.h" |
||
11 | #include "dbg.h" |
||
12 | |||
13 | 9cc07b6c | Csaba Kiraly | static const char *output_format = "nut"; |
14 | 1a8f1a2d | Csaba Kiraly | static const char *output_file = "/dev/stdout"; |
15 | 9cc07b6c | Csaba Kiraly | |
16 | 529d08a9 | Csaba Kiraly | static int64_t prev_pts, prev_dts;
|
17 | |||
18 | 5557f497 | Luca Abeni | static enum CodecID libav_codec_id(uint8_t mytype) |
19 | { |
||
20 | switch (mytype) {
|
||
21 | case 1: |
||
22 | return CODEC_ID_MPEG2VIDEO;
|
||
23 | case 2: |
||
24 | return CODEC_ID_H261;
|
||
25 | case 3: |
||
26 | return CODEC_ID_H263P;
|
||
27 | case 4: |
||
28 | return CODEC_ID_MJPEG;
|
||
29 | case 5: |
||
30 | return CODEC_ID_MPEG4;
|
||
31 | case 6: |
||
32 | return CODEC_ID_FLV1;
|
||
33 | case 7: |
||
34 | return CODEC_ID_SVQ3;
|
||
35 | case 8: |
||
36 | return CODEC_ID_DVVIDEO;
|
||
37 | case 9: |
||
38 | return CODEC_ID_H264;
|
||
39 | case 10: |
||
40 | return CODEC_ID_THEORA;
|
||
41 | case 11: |
||
42 | return CODEC_ID_SNOW;
|
||
43 | case 12: |
||
44 | return CODEC_ID_VP6;
|
||
45 | case 13: |
||
46 | return CODEC_ID_DIRAC;
|
||
47 | default:
|
||
48 | fprintf(stderr, "Unknown codec %d\n", mytype);
|
||
49 | return 0; |
||
50 | } |
||
51 | } |
||
52 | |||
53 | 0afd03fd | Luca Abeni | static AVFormatContext *format_init(const uint8_t *data) |
54 | { |
||
55 | AVFormatContext *of; |
||
56 | AVCodecContext *c; |
||
57 | AVOutputFormat *outfmt; |
||
58 | int width, height, frame_rate_n, frame_rate_d;
|
||
59 | |||
60 | av_register_all(); |
||
61 | |||
62 | width = data[1] << 8 | data[2]; |
||
63 | height = data[3] << 8 | data[4]; |
||
64 | frame_rate_n = data[5] << 8 | data[6]; |
||
65 | frame_rate_d = data[7] << 8 | data[8]; |
||
66 | dprintf("Frame size: %dx%d -- Frame rate: %d / %d\n", width, height, frame_rate_n, frame_rate_d);
|
||
67 | |||
68 | 9cc07b6c | Csaba Kiraly | outfmt = av_guess_format(output_format, NULL, NULL); |
69 | 0afd03fd | Luca Abeni | of = avformat_alloc_context(); |
70 | if (of == NULL) { |
||
71 | return NULL; |
||
72 | } |
||
73 | of->oformat = outfmt; |
||
74 | av_new_stream(of, 0);
|
||
75 | c = of->streams[0]->codec;
|
||
76 | 5557f497 | Luca Abeni | c->codec_id = libav_codec_id(data[0]);
|
77 | 0afd03fd | Luca Abeni | c->codec_type = CODEC_TYPE_VIDEO; |
78 | c->width = width; |
||
79 | c->height= height; |
||
80 | c->time_base.den = frame_rate_n; |
||
81 | c->time_base.num = frame_rate_d; |
||
82 | of->streams[0]->avg_frame_rate.num = frame_rate_n;
|
||
83 | of->streams[0]->avg_frame_rate.den = frame_rate_d;
|
||
84 | c->pix_fmt = PIX_FMT_YUV420P; |
||
85 | |||
86 | 529d08a9 | Csaba Kiraly | prev_pts = 0;
|
87 | prev_dts = 0;
|
||
88 | |||
89 | 0afd03fd | Luca Abeni | return of;
|
90 | } |
||
91 | |||
92 | d74bb0e5 | Luca Abeni | void chunk_write(int id, const uint8_t *data, int size) |
93 | { |
||
94 | static AVFormatContext *outctx;
|
||
95 | const int header_size = 1 + 2 + 2 + 2 + 2 + 1; // 1 Frame type + 2 width + 2 height + 2 frame rate num + 2 frame rate den + 1 number of frames |
||
96 | int frames, i;
|
||
97 | |||
98 | 5557f497 | Luca Abeni | if (data[0] > 127) { |
99 | d74bb0e5 | Luca Abeni | fprintf(stderr, "Error! Non video chunk: %x!!!\n", data[0]); |
100 | return;
|
||
101 | } |
||
102 | if (outctx == NULL) { |
||
103 | 0afd03fd | Luca Abeni | outctx = format_init(data); |
104 | d74bb0e5 | Luca Abeni | if (outctx == NULL) { |
105 | 0afd03fd | Luca Abeni | fprintf(stderr, "Format init failed\n");
|
106 | |||
107 | d74bb0e5 | Luca Abeni | return;
|
108 | } |
||
109 | av_set_parameters(outctx, NULL);
|
||
110 | 9cc07b6c | Csaba Kiraly | snprintf(outctx->filename, sizeof(outctx->filename), "%s", output_file); |
111 | dump_format(outctx, 0, output_file, 1); |
||
112 | url_fopen(&outctx->pb, output_file, URL_WRONLY); |
||
113 | d74bb0e5 | Luca Abeni | av_write_header(outctx); |
114 | } |
||
115 | |||
116 | frames = data[9];
|
||
117 | for (i = 0; i < frames; i++) { |
||
118 | AVPacket pkt; |
||
119 | 3b1df622 | Luca Abeni | int32_t pts, dts; |
120 | int frame_size;
|
||
121 | d74bb0e5 | Luca Abeni | |
122 | 3b1df622 | Luca Abeni | frame_size = data[10 + (2 + 2 + 2) * i] << 8 | data[11 + (2 + 2 + 2) * i]; |
123 | pts = data[12 + (2 + 2 + 2) * i] << 8 | data[13 + (2 + 2 + 2) * i]; |
||
124 | 7a86f98f | Csaba Kiraly | dprintf("Frame %d PTS1: %d\n", i, pts);
|
125 | 529d08a9 | Csaba Kiraly | pts += (pts < prev_pts - (1 << 15)) ? ((prev_pts >> 16) + 1) << 16 : (prev_pts >> 16) << 16; |
126 | 7a86f98f | Csaba Kiraly | dprintf(" PTS2: %d\n", pts);
|
127 | 529d08a9 | Csaba Kiraly | prev_pts = pts; |
128 | 3b1df622 | Luca Abeni | dts = data[14 + (2 + 2 + 2) * i] << 8 | data[15 + (2 + 2 + 2) * i]; |
129 | 529d08a9 | Csaba Kiraly | dts += (dts < prev_dts - (1 << 15)) ? ((prev_dts >> 16) + 1) << 16 : (prev_dts >> 16) << 16; |
130 | prev_dts = dts; |
||
131 | 3b1df622 | Luca Abeni | dprintf("Frame %d has size %d --- PTS: %lld DTS: %lld\n", i, frame_size,
|
132 | av_rescale_q(pts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q),
|
||
133 | av_rescale_q(dts, outctx->streams[0]->codec->time_base, AV_TIME_BASE_Q));
|
||
134 | d74bb0e5 | Luca Abeni | av_init_packet(&pkt); |
135 | pkt.stream_index = 0; // FIXME! |
||
136 | 3b1df622 | Luca Abeni | pkt.pts = av_rescale_q(pts, outctx->streams[0]->codec->time_base, outctx->streams[0]->time_base); |
137 | pkt.dts = av_rescale_q(dts, outctx->streams[0]->codec->time_base, outctx->streams[0]->time_base); |
||
138 | pkt.data = data + header_size + (i + 1) * (2 + 2 + 2); |
||
139 | pkt.size = frame_size; |
||
140 | d74bb0e5 | Luca Abeni | av_interleaved_write_frame(outctx, &pkt); |
141 | } |
||
142 | } |