Don't crash when exiting playdump
[jpcrr.git] / streamtools / output-drv-x264.cpp
blob9cb41b92315eb78495d037137df6a401c5e3f694
1 #include <cstring>
2 #include "output-drv.hpp"
3 #include <cstdio>
4 #include <stdexcept>
5 #include <vector>
6 #include <string>
7 #include <sstream>
8 #include "rgbtorgb.hh"
10 namespace
12 std::string expand_options(const std::string& opts, uint32_t rn, uint32_t rd)
14 bool insert = true;
15 std::ostringstream ret;
16 if(rd)
17 ret << "--fps " << rn << "/" << rd << " ";
18 for(size_t i = 0; i < opts.length(); i++) {
19 if(insert)
20 ret << " --";
21 insert = false;
22 switch(opts[i]) {
23 case ',':
24 insert = true;
25 break;
26 case '=':
27 ret << " ";
28 break;
29 default:
30 ret << opts[i];
33 ret << " ";
34 return ret.str();
37 class output_driver_x264 : public output_driver
39 public:
40 output_driver_x264(const std::string& _filename, const std::string& _options)
42 filename = _filename;
43 options = _options;
44 set_video_callback<output_driver_x264>(*this, &output_driver_x264::video_callback);
47 ~output_driver_x264()
49 pclose(out);
52 void ready()
54 const video_settings& v = get_video_settings();
55 framesize = 4 * v.get_width() * v.get_height();
56 width = v.get_width();
58 std::stringstream commandline;
59 commandline << "x264 ";
60 commandline << expand_options(options, v.get_rate_num(), v.get_rate_denum());
61 commandline << "- -o " << filename << " " << v.get_width() << "x" << v.get_height();
62 std::string s = commandline.str();
63 out = popen(s.c_str(), "w");
64 if(!out) {
65 std::stringstream str;
66 str << "Can't run x264 (" << s << ")";
67 throw std::runtime_error(str.str());
71 void video_callback(uint64_t timestamp, const uint8_t* raw_rgbx_data)
73 std::vector<unsigned char> tmp(framesize * 3 / 8);
74 size_t primarysize = framesize / 4;
75 size_t offs1 = primarysize / 4;
76 size_t offs2 = 0;
77 Convert32To_I420Frame(raw_rgbx_data, &tmp[0], framesize / 4, width);
78 size_t r;
79 if((r = fwrite(&tmp[0], 1, primarysize, out)) < primarysize) {
80 std::stringstream str;
81 str << "Error writing frame to x264 (requested " << primarysize << ", got " << r << ")";
82 throw std::runtime_error(str.str());
84 //Swap U and V.
85 if((r = fwrite(&tmp[primarysize + offs1], 1, primarysize / 4, out)) < primarysize / 4) {
86 std::stringstream str;
87 str << "Error writing frame to x264 (requested " << primarysize / 4 << ", got " << r << ")";
88 throw std::runtime_error(str.str());
90 if((r = fwrite(&tmp[primarysize + offs2], 1, primarysize / 4, out)) < primarysize / 4) {
91 std::stringstream str;
92 str << "Error writing frame to x264 (requested " << primarysize / 4 << ", got " << r << ")";
93 throw std::runtime_error(str.str());
96 private:
97 FILE* out;
98 std::string filename;
99 std::string options;
100 size_t framesize;
101 size_t width;
104 class output_driver_x264_factory : output_driver_factory
106 public:
107 output_driver_x264_factory()
108 : output_driver_factory("x264")
112 output_driver& make(const std::string& type, const std::string& name, const std::string& parameters)
114 return *new output_driver_x264(name, parameters);
116 } factory;