#include <iomanip>
#include <sstream>
#include <iostream>
+#include <fstream>
#include <unistd.h>
#include <errno.h>
#include <boost/array.hpp>
#include "scaler.h"
#include "image.h"
#include "log.h"
-
-#ifdef DEBUG_HASH
-#include <mhash.h>
-#endif
+#include "subtitle.h"
using namespace std;
using namespace boost;
* @param l Log to write to.
*/
DCPVideoFrame::DCPVideoFrame (
- shared_ptr<Image> yuv, Size out, int p, Scaler const * s, int f, float fps, string pp, int clut, int bw, Log* l)
+ shared_ptr<Image> yuv, shared_ptr<Subtitle> sub,
+ Size out, int p, int subtitle_offset, float subtitle_scale,
+ Scaler const * s, int f, float fps, string pp, int clut, int bw, Log* l
+ )
: _input (yuv)
+ , _subtitle (sub)
, _out_size (out)
, _padding (p)
+ , _subtitle_offset (subtitle_offset)
+ , _subtitle_scale (subtitle_scale)
, _scaler (s)
, _frame (f)
/* we round here; not sure if this is right */
shared_ptr<EncodedData>
DCPVideoFrame::encode_locally ()
{
- shared_ptr<Image> prepared = _input;
-
if (!_post_process.empty ()) {
- prepared = prepared->post_process (_post_process);
+ _input = _input->post_process (_post_process);
}
- prepared = prepared->scale_and_convert_to_rgb (_out_size, _padding, _scaler);
+ shared_ptr<Image> prepared = _input->scale_and_convert_to_rgb (_out_size, _padding, _scaler);
+
+ if (_subtitle) {
+ list<shared_ptr<SubtitleImage> > subs = _subtitle->images ();
+ for (list<shared_ptr<SubtitleImage> >::iterator i = subs.begin(); i != subs.end(); ++i) {
+ Rectangle tx = transformed_subtitle_area (
+ float (_out_size.width) / _input->size().width,
+ float (_out_size.height) / _input->size().height,
+ (*i)->area(), _subtitle_offset, _subtitle_scale
+ );
+
+ shared_ptr<Image> im = (*i)->image()->scale (Size (tx.w, tx.h), _scaler);
+ prepared->alpha_blend (im, Position (tx.x, tx.y));
+ }
+ }
create_openjpeg_container ();
- int const size = _out_size.width * _out_size.height;
-
struct {
double r, g, b;
} s;
/* Copy our RGB into the openjpeg container, converting to XYZ in the process */
- uint8_t* p = prepared->data()[0];
- for (int i = 0; i < size; ++i) {
- /* In gamma LUT (converting 8-bit input to 12-bit) */
- s.r = lut_in[_colour_lut_index][*p++ << 4];
- s.g = lut_in[_colour_lut_index][*p++ << 4];
- s.b = lut_in[_colour_lut_index][*p++ << 4];
-
- /* RGB to XYZ Matrix */
- d.x = ((s.r * color_matrix[_colour_lut_index][0][0]) + (s.g * color_matrix[_colour_lut_index][0][1]) + (s.b * color_matrix[_colour_lut_index][0][2]));
- d.y = ((s.r * color_matrix[_colour_lut_index][1][0]) + (s.g * color_matrix[_colour_lut_index][1][1]) + (s.b * color_matrix[_colour_lut_index][1][2]));
- d.z = ((s.r * color_matrix[_colour_lut_index][2][0]) + (s.g * color_matrix[_colour_lut_index][2][1]) + (s.b * color_matrix[_colour_lut_index][2][2]));
-
- /* DCI companding */
- d.x = d.x * DCI_COEFFICENT * (DCI_LUT_SIZE - 1);
- d.y = d.y * DCI_COEFFICENT * (DCI_LUT_SIZE - 1);
- d.z = d.z * DCI_COEFFICENT * (DCI_LUT_SIZE - 1);
-
- /* Out gamma LUT */
- _image->comps[0].data[i] = lut_out[LO_DCI][(int) d.x];
- _image->comps[1].data[i] = lut_out[LO_DCI][(int) d.y];
- _image->comps[2].data[i] = lut_out[LO_DCI][(int) d.z];
+ int jn = 0;
+ for (int y = 0; y < _out_size.height; ++y) {
+ uint8_t* p = prepared->data()[0] + y * prepared->stride()[0];
+ for (int x = 0; x < _out_size.width; ++x) {
+
+ /* In gamma LUT (converting 8-bit input to 12-bit) */
+ s.r = lut_in[_colour_lut_index][*p++ << 4];
+ s.g = lut_in[_colour_lut_index][*p++ << 4];
+ s.b = lut_in[_colour_lut_index][*p++ << 4];
+
+ /* RGB to XYZ Matrix */
+ d.x = ((s.r * color_matrix[_colour_lut_index][0][0]) +
+ (s.g * color_matrix[_colour_lut_index][0][1]) +
+ (s.b * color_matrix[_colour_lut_index][0][2]));
+
+ d.y = ((s.r * color_matrix[_colour_lut_index][1][0]) +
+ (s.g * color_matrix[_colour_lut_index][1][1]) +
+ (s.b * color_matrix[_colour_lut_index][1][2]));
+
+ d.z = ((s.r * color_matrix[_colour_lut_index][2][0]) +
+ (s.g * color_matrix[_colour_lut_index][2][1]) +
+ (s.b * color_matrix[_colour_lut_index][2][2]));
+
+ /* DCI companding */
+ d.x = d.x * DCI_COEFFICENT * (DCI_LUT_SIZE - 1);
+ d.y = d.y * DCI_COEFFICENT * (DCI_LUT_SIZE - 1);
+ d.z = d.z * DCI_COEFFICENT * (DCI_LUT_SIZE - 1);
+
+ /* Out gamma LUT */
+ _image->comps[0].data[jn] = lut_out[LO_DCI][(int) d.x];
+ _image->comps[1].data[jn] = lut_out[LO_DCI][(int) d.y];
+ _image->comps[2].data[jn] = lut_out[LO_DCI][(int) d.z];
+
+ ++jn;
+ }
}
/* Set the max image and component sizes based on frame_rate */
/* Set event manager to null (openjpeg 1.3 bug) */
_cinfo->event_mgr = 0;
-#ifdef DEBUG_HASH
- md5_data ("J2K in X frame " + lexical_cast<string> (_frame), _image->comps[0].data, size * sizeof (int));
- md5_data ("J2K in Y frame " + lexical_cast<string> (_frame), _image->comps[1].data, size * sizeof (int));
- md5_data ("J2K in Z frame " + lexical_cast<string> (_frame), _image->comps[2].data, size * sizeof (int));
-#endif
-
/* Setup the encoder parameters using the current image and user parameters */
opj_setup_encoder (_cinfo, _parameters, _image);
throw EncodeError ("jpeg2000 encoding failed");
}
-#ifdef DEBUG_HASH
- md5_data ("J2K out frame " + lexical_cast<string> (_frame), _cio->buffer, cio_tell (_cio));
-#endif
-
- {
- stringstream s;
- s << "Finished locally-encoded frame " << _frame;
- _log->log (s.str ());
- }
+ _log->log (String::compose ("Finished locally-encoded frame %1", _frame));
return shared_ptr<EncodedData> (new LocallyEncodedData (_cio->buffer, cio_tell (_cio)));
}
{
asio::io_service io_service;
asio::ip::tcp::resolver resolver (io_service);
-
asio::ip::tcp::resolver::query query (serv->host_name(), boost::lexical_cast<string> (Config::instance()->server_port ()));
asio::ip::tcp::resolver::iterator endpoint_iterator = resolver.resolve (query);
- shared_ptr<asio::ip::tcp::socket> socket (new asio::ip::tcp::socket (io_service));
-
- DeadlineWrapper wrapper (io_service);
- wrapper.set_socket (socket);
+ Socket socket;
- wrapper.connect (*endpoint_iterator, 30);
-
-#ifdef DEBUG_HASH
- _input->hash ("Input for remote encoding (before sending)");
-#endif
+ socket.connect (*endpoint_iterator, 30);
stringstream s;
s << "encode "
<< _input->pixel_format() << " "
<< _out_size.width << " " << _out_size.height << " "
<< _padding << " "
+ << _subtitle_offset << " "
+ << _subtitle_scale << " "
<< _scaler->id () << " "
<< _frame << " "
<< _frames_per_second << " "
<< Config::instance()->colour_lut_index () << " "
<< Config::instance()->j2k_bandwidth () << " ";
- for (int i = 0; i < _input->components(); ++i) {
- s << _input->line_size()[i] << " ";
- }
-
- wrapper.write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30);
+ socket.write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30);
for (int i = 0; i < _input->components(); ++i) {
- wrapper.write (_input->data()[i], _input->line_size()[i] * _input->lines(i), 30);
+ socket.write (_input->data()[i], _input->stride()[i] * _input->lines(i), 30);
}
char buffer[32];
- wrapper.read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30);
- wrapper.consume (strlen (buffer) + 1);
+ socket.read_indefinite ((uint8_t *) buffer, sizeof (buffer), 30);
+ socket.consume (strlen (buffer) + 1);
shared_ptr<EncodedData> e (new RemotelyEncodedData (atoi (buffer)));
/* now read the rest */
- wrapper.read_definite_and_consume (e->data(), e->size(), 30);
-
-#ifdef DEBUG_HASH
- e->hash ("Encoded image (after receiving)");
-#endif
+ socket.read_definite_and_consume (e->data(), e->size(), 30);
- {
- stringstream s;
- s << "Finished remotely-encoded frame " << _frame;
- _log->log (s.str ());
- }
+ _log->log (String::compose ("Finished remotely-encoded frame %1", _frame));
return e;
}
fwrite (_data, 1, _size, f);
fclose (f);
+ string const real_j2k = opt->frame_out_path (frame, false);
+
/* Rename the file from foo.j2c.tmp to foo.j2c now that it is complete */
- filesystem::rename (tmp_j2k, opt->frame_out_path (frame, false));
+ filesystem::rename (tmp_j2k, real_j2k);
+
+ /* Write a file containing the hash */
+ string const hash = real_j2k + ".md5";
+ ofstream h (hash.c_str());
+ h << md5_digest (_data, _size) << "\n";
+ h.close ();
}
/** Send this data to a socket.
* @param socket Socket
*/
void
-EncodedData::send (DeadlineWrapper& wrapper)
+EncodedData::send (shared_ptr<Socket> socket)
{
stringstream s;
s << _size;
- wrapper.write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30);
- wrapper.write (_data, _size, 30);
-}
-
-#ifdef DEBUG_HASH
-void
-EncodedData::hash (string n) const
-{
- md5_data (n, _data, _size);
+ socket->write ((uint8_t *) s.str().c_str(), s.str().length() + 1, 30);
+ socket->write (_data, _size, 30);
}
-#endif
/** @param s Size of data in bytes */
RemotelyEncodedData::RemotelyEncodedData (int s)